home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / eulisp / telos-cl.lha / telos-cl.lsp next >
Lisp/Scheme  |  1993-08-09  |  81KB  |  2,353 lines

  1. #|
  2. Telos in Common Lisp.  Copyright (C) Russell Bradford, August 1992,
  3. rjb@maths.bath.ac.uk.
  4.  
  5. For educational use only.
  6.  
  7. An implementation of Telos as taken from the EuLisp document version 0.95,
  8. and from the "Balancing" paper by Harry Bretthauer et al.
  9.  
  10. There are some differences with the above descriptions, mostly due to
  11. the 2-valued nature of CL, some due to a passing attempt to integrate with the
  12. usual type hierarchy of CL, others due to laziness on my part.
  13.  
  14. Disclaimer: this code was written to help me to understand Telos and MOPs
  15. in general.  Thus there are probably many features, naiveities, or even bugs.
  16. Plus the optimisations are somewhat simplistic.  I am interested in
  17. hearing about bugs/improvements and so on, but won't necessarily act upon
  18. them.
  19.  
  20. Developed on AKCL, has run on CMU, Clisp, HCL and WCL in its lifetime.  Works
  21. best when compiled: otherwise somewhat slow!  See the documentation strings for
  22. defclass, defgeneric, defmethod for more information.
  23.  
  24. Added attractions:
  25. describe tells you much about an object.
  26. defstructure is a simple implementation of structures.
  27. class-hierarchy gives the current subclass hierarchy.
  28. instance-hierarchy gives the current class instance hierarchy.
  29.  
  30. Version 2.0:  First released version RJB 92/10/27
  31.         2.1:  Fixed bug in sorting applicable methods that was revealed by MI
  32.               module RJB 92/10/29
  33. |#
  34.  
  35. (in-package :telos)
  36.  
  37. (shadow '(describe
  38.           #+KCL allocate
  39.           #+CMU stream))
  40.  
  41. (export '(generic-funcall primitive-ref primitive-class-of primitive-allocate
  42.       metaclass class abstract-class function-class object generic-function
  43.       method slot-description local-slot-description
  44.       class-of subclass? class? slot-description?
  45.       generic-function? method? defgeneric method-function-lambda
  46.       defmethod class-name class-instance-length class-direct-superclasses
  47.       class-direct-subclasses class-slot-descriptions class-initargs
  48.       class-precedence-list generic-function-name generic-function-domain
  49.       generic-function-method-class generic-function-method-initargs
  50.       generic-function-methods generic-function-method-lookup-function
  51.       generic-function-discriminating-function generic-function-cache
  52.       method-generic-function method-domain
  53.       method-function slot-description-name slot-description-initfunction
  54.       slot-description-slot-reader slot-description-slot-writer
  55.       slot-value-using-slot-description find-slot-description
  56.       slot-value make allocate initialize call-next-method
  57.       next-method? apply-method call-method compute-method-lookup-function
  58.       compute-discriminating-function add-method remove-method
  59.       find-method compatible-superclasses-p compatible-superclass-p
  60.       compute-class-precedence-list compute-inherited-initargs
  61.       compute-initargs compute-inherited-slot-descriptions
  62.       compute-slot-descriptions compute-specialized-slot-description
  63.       compute-specialized-slot-description-class
  64.       compute-defined-slot-description
  65.       compute-defined-slot-description-class
  66.       copy-object compute-and-ensure-slot-accessors compute-slot-reader
  67.       compute-slot-writer ensure-slot-reader
  68.       compute-primitive-reader-using-slot-description
  69.       compute-primitive-reader-using-class
  70.       ensure-slot-writer compute-primitive-writer-using-slot-description
  71.       compute-primitive-writer-using-class add-subclass defclass
  72.       defmetaclass generic-prin common cl-object class-hierarchy
  73.       instance-hierarchy structure-class structure defstructure
  74.       describe standard-function find-key required))
  75.  
  76. ;(eval-when (compile)
  77. ;   (proclaim '(optimize (speed 3) (safety 0) (compilation-speed 0))))
  78.  
  79. ;#+AKCL (use-fast-links nil)
  80.  
  81. #+KCL
  82. (eval-when (load)
  83.   (format t "loading..."))
  84.  
  85. (defun generic-funcall (fun &rest args)
  86.   (cond ((functionp fun) (apply fun args))
  87.     ((generic-function? fun)
  88.      (apply (generic-function-discriminating-function fun) args))
  89.     (t (error "~a is not a function in GENERIC-FUNCALL" fun))))
  90.  
  91. (eval-when (compile load eval)
  92.  
  93. (defvar telos (find-package :telos)
  94.   "The Telos Package")
  95.  
  96. ) ; end of eval-when
  97.  
  98. (eval-when (compile)
  99.  
  100. (proclaim '(inline primitive-class-slots primitive-class-class
  101.            primitive-ref setter-primitive-ref
  102.            primitive-class-of setter-primitive-class-of))
  103.  
  104. ) ; end of eval-when
  105.  
  106. (defstruct (primitive-class (:print-function primitive-print))
  107.   class
  108.   slots)
  109.  
  110. (defun primitive-ref (s n)
  111.   (svref (primitive-class-slots s) n))
  112.  
  113. (defun setter-primitive-ref (s n v)
  114.   (setf (svref (primitive-class-slots s) n) v))
  115.  
  116. (defsetf primitive-ref setter-primitive-ref)
  117.  
  118. (defun primitive-class-of (cl)
  119.   (primitive-class-class cl))
  120.  
  121. (defun setter-primitive-class-of (cl val)
  122.   (setf (primitive-class-class cl) val))
  123.  
  124. (defsetf primitive-class-of setter-primitive-class-of)
  125.  
  126. (defvar unbound (list 'unbound))
  127.  
  128. (defun unbound () unbound)
  129.  
  130. (defun primitive-allocate (cl size)
  131.   (make-primitive-class :class cl
  132.             :slots (make-array size :initial-element unbound)))
  133.  
  134.  
  135. ; object
  136. (defconstant object-slots ())
  137. (defconstant object-initargs ())
  138. (defconstant object-size 0)
  139.  
  140. ; class
  141. (defconstant %name 0)
  142. (defconstant %instance-length 1)
  143. (defconstant %direct-superclasses 2)
  144. (defconstant %direct-subclasses 3)
  145. (defconstant %slot-descriptions 4)
  146. (defconstant %initargs 5)
  147. (defconstant %precedence-list 6)
  148. (defconstant class-slots '(name instance-length direct-superclasses
  149.                direct-subclasses slot-descriptions
  150.                initargs class-precedence-list))
  151. (defconstant class-accessors '(class-name class-instance-length
  152.                    class-direct-superclasses
  153.                    class-direct-subclasses
  154.                    class-slot-descriptions class-initargs
  155.                    class-precedence-list))
  156. (defconstant class-inits '(:name :direct-superclasses :direct-slot-descriptions
  157.                :direct-initargs))
  158. (defconstant class-size (length class-slots))
  159.  
  160.  
  161. ; generic-function
  162. ;(defconstant %name 0)
  163. (defconstant %domain 1)
  164. (defconstant %method-class 2)
  165. (defconstant %method-initargs 3)
  166. (defconstant %methods 4)
  167. (defconstant %method-lookup-function 5)
  168. (defconstant %discriminating-function 6)
  169. (defconstant %cache 7)
  170. (defconstant gf-slots '(name domain method-class method-initargs methods
  171.             method-lookup-function discriminating-function
  172.             cache))
  173. (defconstant gf-accessors '(generic-function-name generic-function-domain
  174.                 generic-function-method-class
  175.                 generic-function-method-initargs
  176.                 generic-function-methods
  177.                 generic-function-method-lookup-function
  178.                 generic-function-discriminating-function
  179.                 generic-function-cache))
  180. (defconstant gf-initargs '(:name :domain :method-class :method-initargs
  181.                :methods :method-lookup-function
  182.                :discriminating-function))
  183. (defconstant gf-size (length gf-slots))
  184.  
  185. ; method
  186. (defconstant %generic-function 0)
  187. ;(defconstant %domain 1)
  188. (defconstant %function 2)
  189. (defconstant method-slots '(generic-function domain function))
  190. (defconstant method-accessors '(method-generic-function method-domain
  191.                 method-function))
  192. (defconstant method-initargs '(:domain :function :generic-function))
  193. (defconstant method-size (length method-slots))
  194.  
  195. ; slot-description
  196. (defconstant %reader 0)
  197. (defconstant %writer 1)
  198. (defconstant sd-slots '(reader writer))
  199. (defconstant sd-accessors '(slot-description-slot-reader
  200.                 slot-description-slot-writer))
  201. (defconstant sd-initargs '(:reader :writer))
  202. (defconstant sd-size (length sd-slots))
  203.  
  204. ; local-slot-description
  205. (defconstant %lsdname 2)
  206. (defconstant %initfunction 3)
  207. (defconstant lsd-slots (append sd-slots '(name initfunction)))
  208. (defconstant lsd-accessors (append sd-accessors
  209.                   '(slot-description-name
  210.                 slot-description-initfunction)))
  211. (defconstant lsd-initargs (append sd-initargs '(:name :initfunction)))
  212. (defconstant lsd-size (length lsd-slots))
  213.  
  214. (defvar metaclass (primitive-allocate () class-size)
  215.   "The Telos metaclass METACLASS")
  216.  
  217. (defvar class (primitive-allocate metaclass class-size)
  218.   "The Telos metaclass CLASS")
  219.  
  220. (defvar abstract-class (primitive-allocate metaclass class-size)
  221.   "The Telos metaclass ABSTRACT-CLASS")
  222.  
  223. (defvar function-class (primitive-allocate metaclass class-size)
  224.   "The Telos metaclass FUNCTION-CLASS")
  225.  
  226. (defvar object (primitive-allocate abstract-class class-size)
  227.   "The Telos abstract class OBJECT")
  228.  
  229. (defvar generic-function (primitive-allocate function-class class-size)
  230.   "The Telos class GENERIC-FUNCTION")
  231.  
  232. (defvar method (primitive-allocate class class-size)
  233.   "The Telos class METHOD")
  234.  
  235. (defvar slot-description (primitive-allocate abstract-class class-size)
  236.   "The Telos abstract class SLOT-DESCRIPTION")
  237.  
  238. (defvar local-slot-description (primitive-allocate class class-size)
  239.   "The Telos class LOCAL-SLOT-DESCRIPTION")
  240.  
  241. ; don't print result
  242. (null (setf (primitive-class-of metaclass) metaclass))
  243.  
  244. ; CL classes
  245.  
  246. (defvar common (primitive-allocate metaclass class-size)
  247.   "The Telos metaclass COMMON")
  248.  
  249. (defvar cl-object (primitive-allocate abstract-class class-size)
  250.   "The Telos abstract class CL-OBJECT")
  251.  
  252. (defmacro memq (a b) `(member ,a ,b :test #'eq))
  253.  
  254. (defconstant cl-class-table (make-hash-table :test #'eq))
  255.  
  256. ; This will be overwritten later when we get around to defining CL classes.
  257. ; Hack due to (type-of ()) -> SYMBOL, not NULL as we might hope.
  258. (defvar null () "The Telos class NULL")
  259.  
  260. #-KCL
  261. (defun class-of (obj)
  262.   (cond ((primitive-class-p obj) (primitive-class-of obj))
  263.     ((null obj) null)
  264.     (t (let ((type (type-of obj)))
  265.          (or (gethash type cl-class-table)
  266.          (when (consp type) 
  267.            (gethash (car type) cl-class-table))
  268.          object)))))
  269.  
  270. ; KCL uses conses for lambdas
  271. #+KCL
  272. (defvar standard-function () "The Telos class STANDARD FUNCTION")
  273. #+KCL
  274. (defun class-of (obj)
  275.   (cond ((primitive-class-p obj) (primitive-class-of obj))
  276.         ((null obj) null)
  277.     ((and (consp obj) (functionp obj)) standard-function)
  278.         (t (let ((type (type-of obj)))
  279.              (or (gethash type cl-class-table)
  280.                  (when (consp type)
  281.                    (gethash (car type) cl-class-table))
  282.                  object)))))
  283.  
  284. (defvar primitive-metaclasses
  285.   (list metaclass function-class abstract-class class common))
  286.  
  287. (defun primitive-metaclass? (obj)
  288.   (memq obj primitive-metaclasses))
  289.  
  290. ; assume both are classes
  291. (defun subclass? (a b)
  292.   (cond ((eq a b) t)
  293.      ((null a) ())
  294.      (t (some #'(lambda (c) (subclass? c b))
  295.           (if (primitive-metaclass? (class-of a))
  296.              (primitive-ref a %direct-superclasses)
  297.              (class-direct-superclasses a))))))
  298.  
  299. (defun cpl-subclass? (a b)
  300.   (memq b (if (primitive-metaclass? (class-of a))
  301.           (primitive-ref a %precedence-list)
  302.           (class-precedence-list a))))
  303.  
  304. (defun class? (a) (subclass? (class-of a) class))
  305.  
  306. (defun slot-description? (a) (subclass? (class-of a) slot-description))
  307.  
  308. (defun generic-function? (a) (subclass? (class-of a) generic-function))
  309.  
  310. (defun method? (a) (subclass? (class-of a) method))
  311.  
  312. #+telos-debug (progn
  313.  
  314. ; temporary version while debugging
  315. ; take care to avoid any gf calls
  316. (defun primitive-print (obj str xx)
  317.   (declare (ignore xx))
  318.   (primitive-generic-prin obj str))
  319.  
  320. (defvar primitive-classes
  321.   (list object class metaclass abstract-class function-class generic-function
  322.     method slot-description local-slot-description))
  323.  
  324. (defun primitive-generic-prin (obj str)
  325.   (let ((cl (primitive-class-of obj)))
  326.     (cond ((or (memq obj primitive-classes)
  327.            (primitive-metaclass? cl))
  328.        (format str "#class(~s [~s])"
  329.            (primitive-ref obj %name)
  330.            (primitive-ref cl %name)))
  331.       ((eq cl local-slot-description)
  332.        (format str "#slotd(~s)"
  333.            (primitive-ref obj %lsdname)))
  334.       ((eq cl generic-function)
  335.        (format str "#gfun~s"
  336.            (cons (primitive-ref obj %name)
  337.              (mapcar #'(lambda (o) (primitive-ref o %name))
  338.                  (primitive-ref obj %domain)))))
  339.       ((eq cl method)
  340.        (format str "#method~s"
  341.            (cons (if (generic-function?
  342.                   (primitive-ref obj %generic-function))
  343.                  (primitive-ref
  344.                   (primitive-ref obj %generic-function)
  345.                   %name)
  346.                  :unattached)
  347.               (mapcar #'(lambda (o) (primitive-ref o %name))
  348.                   (primitive-ref obj %domain)))))
  349.       (t (format str "#object([~s])"
  350.              (primitive-ref cl %name))))) obj)
  351.  
  352. ) ; end of telos-debug
  353.  
  354. (defun init-class (cl name isize supers subs inits cpl)
  355.   (setf (primitive-ref cl %name) name)
  356.   (setf (primitive-ref cl %instance-length) isize)
  357.   (setf (primitive-ref cl %direct-superclasses) supers)
  358.   (setf (primitive-ref cl %direct-subclasses) subs)
  359.   (setf (primitive-ref cl %slot-descriptions) ())
  360.   (setf (primitive-ref cl %initargs) inits)
  361.   (setf (primitive-ref cl %precedence-list) (cons cl cpl))
  362.   name)
  363.  
  364. (init-class object 'object object-size ()
  365.         (list class method slot-description cl-object)
  366.         () ())
  367. (init-class class 'class class-size (list object)
  368.         (list metaclass abstract-class function-class common)
  369.         class-inits (list object))
  370. (init-class metaclass 'metaclass class-size (list class) () class-inits
  371.         (list class object))
  372. (init-class abstract-class 'abstract-class class-size (list class) ()
  373.         class-inits (list class object))
  374. (init-class function-class 'function-class class-size (list class) ()
  375.         class-inits (list class object))
  376. ;(init-class generic-function 'generic-function gf-size (list object) ()
  377. ;        gf-initargs (list object))
  378. (init-class method 'method method-size (list object) ()
  379.         method-initargs (list object))
  380. (init-class slot-description 'slot-description sd-size (list object)
  381.         (list local-slot-description) sd-initargs (list object))
  382. (init-class local-slot-description 'local-slot-description lsd-size
  383.         (list slot-description) () lsd-initargs
  384.         (list slot-description object))
  385. (init-class common 'common class-size (list class) () class-inits
  386.         (list class object))
  387. (init-class cl-object 'cl-object object-size (list object) ()
  388.         () (list object))
  389.  
  390. ; CL classes
  391.  
  392. (defmacro def-cl-class (name supers cpl)
  393.   `(progn
  394.      (defvar ,name () ,(format () "The Telos class ~a" name))
  395.      (setq ,name (primitive-allocate common class-size))
  396.      (setf (primitive-ref ,name %name) ',name)
  397.      (setf (primitive-ref ,name %instance-length) 0)
  398.      (setf (primitive-ref ,name %direct-superclasses) (list ,@supers))
  399.      (setf (primitive-ref ,name %direct-subclasses) ())
  400.      (setf (primitive-ref ,name %slot-descriptions) ())
  401.      (setf (primitive-ref ,name %initargs) ())
  402.      (mapc #'(lambda (super)
  403.            (setf (primitive-ref super %direct-subclasses)
  404.              (cons ,name (primitive-ref super %direct-subclasses))))
  405.        (list ,@supers))
  406.      (setf (primitive-ref ,name %precedence-list)
  407.        (cons ,name (append (list ,@cpl) (list cl-object object))))
  408.      (setf (gethash ',name cl-class-table) ,name)
  409.      ',name))
  410.  
  411. (defmacro synonym (a b)
  412.   `(setf (gethash ',a cl-class-table) ,b))
  413.  
  414. (def-cl-class sequence (cl-object) ())
  415. (def-cl-class list (sequence) (sequence))
  416. (def-cl-class cons (list) (list sequence))
  417. (def-cl-class array (cl-object) ())
  418. (synonym simple-array array)
  419. (def-cl-class vector (sequence array) (sequence array))
  420. (synonym simple-vector vector)
  421. (def-cl-class bit-vector (vector) (vector sequence array))
  422. (synonym simple-bit-vector bit-vector)
  423. (def-cl-class string (vector) (vector sequence array))
  424. (synonym simple-string string)
  425. #+KCL (synonym fat-string string)
  426. (def-cl-class symbol (cl-object) ())
  427. (synonym keyword symbol)
  428. (def-cl-class null (list symbol) (list symbol sequence))
  429. (def-cl-class character (cl-object) ())
  430. (synonym string-char character)
  431. (synonym standard-char character)
  432. ;
  433. (def-cl-class function (cl-object) ())
  434. (def-cl-class standard-function (function) (function))
  435. (setf (gethash 'function cl-class-table) standard-function)
  436. (synonym compiled-function standard-function)
  437. ;
  438. (init-class generic-function 'generic-function gf-size (list function) ()
  439.            gf-initargs (list function object))
  440. (setf (primitive-ref function %direct-subclasses)
  441.       (list generic-function standard-function))
  442. ;
  443. (def-cl-class pathname (cl-object) ())
  444. (def-cl-class stream (cl-object) ())
  445. (def-cl-class random-state (cl-object) ())
  446. (def-cl-class hash-table (cl-object) ())
  447. (def-cl-class readtable (cl-object) ())
  448. (def-cl-class package (cl-object) ())
  449. (def-cl-class number (cl-object) ())
  450. (def-cl-class complex (number) (number))
  451. (def-cl-class float (number) (number))
  452. (synonym short-float float)
  453. (synonym single-float float)
  454. (synonym double-float float)
  455. (synonym long-float float)
  456. (def-cl-class rational (number) (number))
  457. (def-cl-class ratio (rational) (rational number))
  458. (def-cl-class integer (rational) (rational number))
  459. (synonym fixnum integer)
  460. (synonym bignum integer)
  461. (synonym bit integer)
  462.  
  463. (defun primitive-find-slot-position (cl name slots index)
  464.   (cond ((null slots)
  465.      (error "slot ~s not found in class ~s" name cl))
  466.      ((eq name (primitive-ref (car slots) %lsdname)) index)
  467.      (t (primitive-find-slot-position cl name (cdr slots) (+ index 1)))))
  468.  
  469. (defun primitive-slot-value (obj name)
  470.   (let ((cl (class-of obj)))
  471.     (primitive-ref obj (primitive-find-slot-position
  472.             cl name
  473.             (primitive-ref cl %slot-descriptions) 0))))
  474.  
  475. (defun setter-primitive-slot-value (obj name val)
  476.   (let ((cl (class-of obj)))
  477.     (setf (primitive-ref obj
  478.        (primitive-find-slot-position cl name
  479.         (primitive-ref cl %slot-descriptions) 0))
  480.       val)))
  481.  
  482. (defsetf primitive-slot-value setter-primitive-slot-value)
  483.  
  484. (defun stable-generic-function-discriminating-function (gf)
  485.   (if (eq (class-of gf) generic-function)
  486.       (primitive-ref gf %discriminating-function)
  487.       (generic-function-discriminating-function gf)))
  488.  
  489. (eval-when (compile load eval)
  490.  
  491. (defun construct-name (fmt &rest args)
  492.   (let ((*print-case* :upcase))
  493.     (intern (apply #'format () fmt args))))
  494.  
  495. (defun reader2writer (name)
  496.   (construct-name "SETTER-~a" name))
  497.  
  498. (defun get-gf-name (name)
  499.   (cond ((symbolp name) name)
  500.      ((and (consp name) (eq (car name) 'setf))
  501.      (reader2writer (cadr name)))
  502.      (t (error "bad name for generic ~a" name))))
  503.  
  504. (defvar required (list 'required))
  505.  
  506. (defun key2symbol (k)
  507.   (if (keywordp k)
  508.       (intern (symbol-name k))
  509.       k))
  510.  
  511. (defun symbol2key (s)
  512.   (if (keywordp s)
  513.       s
  514.       (intern (symbol-name s) :keyword)))
  515.  
  516. (defun find-key (name initargs default)
  517.   (let* ((key (symbol2key name))
  518.       (val (getf initargs key default)))
  519.     (if (eq val required)
  520.      (error "Missing required initarg ~s" name)
  521.      val)))
  522.  
  523. (defun filter-initargs (initargs ignore)
  524.   (cond ((null initargs) ())
  525.      ((memq (car initargs) ignore)
  526.       (filter-initargs (cddr initargs) ignore))
  527.      (t (cons (car initargs)
  528.           (cons (cadr initargs)
  529.                (filter-initargs (cddr initargs) ignore))))))
  530.  
  531. (defun do-defgeneric-methods (name initargs)
  532.   (cond ((null initargs) ())
  533.     ((eq (car initargs) :method)
  534.       (cons `(defmethod ,name ,@(cadr initargs))
  535.            (do-defgeneric-methods name (cddr initargs))))
  536.      (t (do-defgeneric-methods name (cddr initargs)))))
  537.  
  538. (defun required-args (domain)
  539.   (cond ((atom domain) ())
  540.     ((null (cdr domain)) domain)
  541.     ((eq (car domain) '&rest) ())
  542.     (t (cons (car domain)
  543.          (required-args (cdr domain))))))
  544.  
  545. ) ; end of eval-when
  546.  
  547. ; allows (defgeneric (setf foo) ...)
  548. (defmacro defgeneric (gfname arglist . initargs)
  549. "Syntax: (defgeneric gfname (arglist) {initarg}*), where
  550. gfname is {symbol | (setf symbol)},
  551. arglist is {{symbol | (symbol class)}+ [ . symbol ]}, and
  552. initarg is {key val}. Allowable initargs include
  553. :class                   the class of the generic function
  554. :method-class            the class of the associated methods
  555. :method-initargs         a list of {key val} initargs to be passed to
  556.                          calls of defmethod on this gfname
  557. :method                  a method to be attached to the generic function
  558. The :method initarg can be repeated."
  559.   (let* ((gf-class (find-key :class initargs 'generic-function))
  560.      (method-class (find-key :method-class initargs 'method))
  561.      (domain (mapcar #'(lambda (a) (if (atom a) 'object (cadr a)))
  562.              (required-args arglist)))
  563. #+CMU    (args (mapcar #'(lambda (a) (if (atom a) a (car a)))
  564.                (required-args arglist)))
  565.       (name (get-gf-name gfname)))
  566.     `(progn
  567.        (defvar ,name ()
  568.      ,(find-key :documentation initargs
  569.             (format () "The generic function ~a ~a" name arglist)))
  570.        (setq ,name (make-generic-function
  571.             ',name
  572.             (list ,@domain)
  573.             ,gf-class
  574.             ,method-class
  575.             (list ,@(find-key :method-initargs initargs ()))
  576.             (list 
  577.              ,@(filter-initargs
  578.             initargs
  579.             '(:class :method-class :method
  580.               :method-initargs :documentation)))))
  581. #+CMU   (defun ,name ,args (list ,@args))
  582. #-CLISP (setf (symbol-function ',name)
  583.           (stable-generic-function-discriminating-function ,name))
  584. #+CLISP (progn
  585.       (eval-when (compile)
  586.         (system::c-defun ',name))
  587.       (system::remove-old-definitions ',name)
  588.       (system::%putd ',name
  589.         (stable-generic-function-discriminating-function ,name))
  590.       (eval-when (eval)
  591.         (system::%put ',name 'system::definition
  592.           '(defgeneric ,gfname ,arglist ,@initargs))))
  593.        ,@(do-defgeneric-methods name initargs)
  594.        ,@(if (eq name gfname) () `((defsetf ,(cadr gfname) ,name)))
  595.        ',name)))
  596.  
  597. (defun make-generic-function
  598.   (name domain gf-class method-class method-inits initargs)
  599.   (if (and (eq gf-class generic-function)
  600.        (eq method-class method)
  601.        (null method-inits)
  602.        (null initargs))
  603.       (primitive-make-generic-function name domain)
  604.       (apply #'make
  605.          gf-class
  606.          :name name
  607.          :domain domain
  608.          :method-class method-class
  609.          :method-initargs method-inits
  610.          initargs)))
  611.  
  612. (defun primitive-make-generic-function (name domain)
  613.   (let ((gf (primitive-allocate generic-function gf-size)))
  614.     (setf (primitive-ref gf %name) name)
  615.     (setf (primitive-ref gf %domain) domain)
  616.     (setf (primitive-ref gf %method-class) method)
  617.     (setf (primitive-ref gf %method-initargs) ())
  618.     (setf (primitive-ref gf %methods) ())
  619.     (let* ((nargs (length domain))
  620.        (lookup #'(lambda (&rest values)
  621.                (the-method-lookup-function
  622.             gf
  623.             (required-domain values nargs)))))
  624.       (setf (primitive-ref gf %method-lookup-function) lookup)
  625.       (setf (primitive-ref gf %cache) (new-cache))
  626.       (setf (primitive-ref gf %discriminating-function)
  627.         (compute-primitive-discriminating-function gf lookup)))
  628.     gf))
  629.  
  630. (defun check-nargs (gf nvals nargs)
  631.   (unless (>= nvals nargs)
  632.     (error "argument count mismatch: ~a requires ~r argument~:p,
  633. but ~r ~:*~[were~;was~:;were~] supplied"
  634.        gf nargs nvals)))
  635.  
  636. ; cache, c-n-m
  637. ; cf compute-discriminating-function
  638. ; takes same args as the gf
  639. (defun compute-primitive-discriminating-function (gf lookup-fn)
  640.   (let ((cache (primitive-ref gf %cache))
  641.     (nargs (length (primitive-ref gf %domain))))
  642.     #'(lambda (&rest values)
  643.     (check-nargs gf (length values) nargs)
  644.     (let ((applicable (cache-lookup
  645.                values
  646.                (required-domain values nargs)
  647.                cache
  648.                lookup-fn)))
  649.       (if (null applicable)
  650.           (error "no applicable methods ~s:~%arguments:~%~s~%classes:~%~s"
  651.              gf
  652.              values
  653.              (mapcar #'class-of values))
  654.           (apply (car applicable)    ; apply-method
  655.              (cdr applicable)
  656.              values
  657.              values))))))
  658.  
  659. (defun stable-method-function (md)
  660.   (if (eq (class-of md) method)
  661.       (primitive-ref md %function)
  662.       (method-function md)))
  663.  
  664. (defun stable-class-precedence-list (cl)
  665.   (if (primitive-metaclass? cl)
  666.       (primitive-ref cl %precedence-list)
  667.       (class-precedence-list cl)))
  668.  
  669. ; this one gets the correct number of required args
  670. (defun the-method-lookup-function (gf classes)
  671.   (let ((cpls (mapcar #'stable-class-precedence-list classes)))
  672.     (if (and (eq (class-of gf) generic-function)
  673.          (listp classes))
  674.     (primitive-method-lookup-function gf classes cpls)
  675.     (general-method-lookup-function gf classes cpls))))
  676.  
  677. ; note we don't know the class of the methods at this point
  678. (defun primitive-method-lookup-function (gf classes cpls)
  679.   (sort (select-methods classes (primitive-ref gf %methods))
  680.     #'(lambda (md1 md2)
  681.             (sig<= (stable-method-domain md1)
  682.                    (stable-method-domain md2)
  683.                    cpls))))
  684.  
  685. (defun general-method-lookup-function (gf classes cpls)
  686.   (sort (select-methods classes (generic-function-methods gf))
  687.     #'(lambda (md1 md2)
  688.         (sig<= (method-domain md1)
  689.            (method-domain md2)
  690.            cpls))))
  691.  
  692. (defun stable-method-domain (md)
  693.   (if (eq (class-of md) method)
  694.       (primitive-ref md %domain)
  695.       (method-domain md)))
  696.  
  697. ; select-methods copies, as sort is destructive
  698. (defun select-methods (classes meths)
  699.   (if (null meths)
  700.       ()
  701.       (let ((md (car meths)))
  702.     (if (sig-applicable? classes (stable-method-domain md))
  703.         (cons md (select-methods classes (cdr meths)))
  704.         (select-methods classes (cdr meths))))))
  705.  
  706. ; assume equal length
  707. (defun sig-applicable? (m1 m2)
  708.   (cond ((null m1) t)
  709.     ((cpl-subclass? (car m1) (car m2))
  710.      (sig-applicable? (cdr m1) (cdr m2)))
  711.     (t ())))
  712.  
  713. ; assume equal length
  714. (defun sig<= (sig1 sig2 cpls)
  715.   (cond ((null sig1) t)
  716.     ((eq (car sig1) (car sig2))
  717.      (sig<= (cdr sig1) (cdr sig2) (cdr cpls)))
  718.     (t (cpl-preceeds? (car sig1) (car sig2) (car cpls)))))
  719.  
  720. ; must have cl1 and cl2 in cpl
  721. (defun cpl-preceeds? (cl1 cl2 cpl)
  722.   (cond ((eq cl1 (car cpl)) t)
  723.     ((eq cl2 (car cpl)) ())
  724.     (t (cpl-preceeds? cl1 cl2 (cdr cpl)))))
  725.  
  726. ; cache
  727. (defun new-cache ()
  728.   (cons () ()))
  729.  
  730. (defmacro fast-cache (c) `(car ,c))
  731. (defmacro slow-cache (c) `(cdr ,c))
  732.  
  733. (defun reset-cache (cache)
  734.   (setf (fast-cache cache) ())
  735.   (setf (slow-cache cache) ())
  736.   cache)
  737.  
  738. (defun required-domain (values nargs)
  739.   (if (> nargs 0)
  740.       (cons (class-of (car values))
  741.         (required-domain (cdr values) (- nargs 1)))
  742.       ()))
  743.  
  744. ; cache
  745. (defun cache-lookup (values classes cache lookup)
  746.   (let ((fast (fast-cache cache))
  747.     (slow (slow-cache cache)))
  748.     (if (and (consp fast)
  749.          (equal (car fast) classes))
  750.      (cdr fast)
  751.      (let ((cc (member classes slow :test #'equal :key #'car)))
  752.       (if (null cc)
  753.           (let ((applicable (apply lookup values)))
  754.         (if (null applicable)
  755.             ()
  756.             (let ((new (cons classes
  757.                      (cons (stable-method-function
  758.                         (car applicable))
  759.                        (cdr applicable)))))
  760.               (setf (fast-cache cache) new)
  761.               (setf (slow-cache cache) (cons new slow))
  762.               (cdr new))))
  763.           (progn
  764.          (setf (fast-cache cache) (car cc))
  765.          (cdar cc)))))))
  766.  
  767. (eval-when (compile load eval)
  768.  
  769. ; c-n-m
  770. (defmacro method-function-lambda (args . body)
  771.   `#'(lambda (*method-list* *argument-list* ,@args) ,@(block-body () body)))
  772.  
  773. #-KCL
  774. (defmacro named-method-function-lambda (name args . body)
  775.   `#'(lambda (*method-list* *argument-list* ,@args) ,@(block-body name body)))
  776.  
  777. (defun block-body (gfname body)
  778.   (if (consp body)
  779.       (cond ((stringp (car body))
  780.          (if (null (cdr body))
  781.          body
  782.          (block-body gfname (cdr body))))
  783.         ((and (consp (car body))
  784.           (eq (caar body) 'declare))
  785.          `(,(car body) ,@(block-body gfname (cdr body))))
  786.         (t (if (null gfname)
  787.            `((progn *method-list* *argument-list*)
  788.                 ,@body)
  789.            `((block ,gfname *method-list* *argument-list* ,@body)))))
  790.       ()))
  791.  
  792. )
  793.  
  794. ; (defmethod foo ((a integer)...) ...)
  795. ; (defmethod foo :method-initarg 23 ... ((a integer)...) ...)
  796. ; allows (defmethod (setf foo) ...)
  797. #-KCL
  798. (defmacro defmethod (gfun . form)
  799.   "Syntax: (defmethod gfname {key val}* (arglist) {form}*), where
  800. gfname is {symbol | (setf symbol)}, and arglist is
  801. {{symbol | (symbol class)}+ [ . symbol ]}"
  802.   (let* ((initargs (defmethod-initargs form))
  803.      (sig (defmethod-sig form))
  804.      (body (defmethod-body form))
  805.      (inits (filter-initargs initargs '(:class)))
  806.      (method-class (find-key :class initargs ()))
  807.      (args (defmethod-args sig))
  808.      (domain (defmethod-domain sig))
  809.      (gfn (get-gf-name gfun)))
  810.     `(stable-add-method
  811.       ,gfn
  812.       (make-method ,(if (null method-class)
  813.             `(stable-generic-function-method-class ,gfn)
  814.             method-class)
  815.            (list ,@domain)
  816.            (named-method-function-lambda ,gfn ,args ,@body)
  817.            (append
  818.             (list ,@inits)
  819.             (stable-generic-function-method-initargs ,gfn))))))
  820.  
  821. ;; KCL has problems compiling the above due to
  822. ;; a combination of not bothering to macroexpand at compile time and
  823. ;; an inability to compile lambdas in random locations
  824. #+KCL
  825. (defmacro defmethod (gfun . form)
  826.   "Syntax: (defmethod gfname {key val}* (arglist) {form}*), where
  827. gfname is {symbol | (setf symbol)}, and arglist is
  828. {{symbol | (symbol class)}+ [ . symbol ]}"
  829.   (let* ((initargs (defmethod-initargs form))
  830.      (sig (defmethod-sig form))
  831.      (body (defmethod-body form))
  832.      (inits (filter-initargs initargs '(:class)))
  833.      (method-class (find-key :class initargs ()))
  834.      (args (defmethod-args sig))
  835.      (domain (defmethod-domain sig))
  836.      (gfn (get-gf-name gfun))
  837.      (ml (gensym (format () "~a/METHOD" gfn))))
  838.     `(progn
  839.        (defun ,ml (*method-list* *argument-list* ,@args) ; c-n-m
  840.      ,@(block-body gfn body))
  841.        (stable-add-method
  842.     ,gfn
  843.     (make-method ,(if (null method-class)
  844.               `(stable-generic-function-method-class ,gfn)
  845.               method-class)
  846.              (list ,@domain)
  847.              #',ml
  848.              (append
  849.               (list ,@inits)
  850.               (stable-generic-function-method-initargs ,gfn)))))))
  851.  
  852. (eval-when (compile load eval)
  853.  
  854. (defun defmethod-initargs (form)
  855.   (if (atom (car form))
  856.       (cons (car form)
  857.         (cons (cadr form) (defmethod-initargs (cddr form))))
  858.       ()))
  859.  
  860. (defun defmethod-sig (form)
  861.   (if (atom (car form))
  862.       (defmethod-sig (cddr form))
  863.       (car form)))
  864.  
  865. (defun defmethod-body (form)
  866.   (if (atom (car form))
  867.       (defmethod-body (cddr form))
  868.       (cdr form)))
  869.  
  870. (defun defmethod-args (sig)
  871.   (cond ((atom sig) (list '&rest sig))
  872.     ((null (cdr sig)) (list (if (atom (car sig)) (car sig) (caar sig))))
  873.     ((eq (car sig) '&rest) sig)
  874.     (t (cons (if (atom (car sig)) (car sig) (caar sig))
  875.          (defmethod-args (cdr sig))))))
  876.  
  877. (defun defmethod-domain (sig)
  878.   (cond ((atom sig) ())
  879.     ((null (cdr sig)) (list (if (atom (car sig)) 'object (cadar sig))))
  880.     ((eq (car sig) '&rest) ())
  881.     (t (cons (if (atom (car sig)) 'object (cadar sig))
  882.          (defmethod-domain (cdr sig))))))
  883.  
  884. ) ; end of eval-when
  885.  
  886. (defun stable-generic-function-method-class (gf)
  887.   (if (eq (class-of gf) generic-function)
  888.       (primitive-ref gf %method-class)
  889.       (generic-function-method-class gf)))
  890.  
  891. (defun stable-generic-function-method-initargs (gf)
  892.   (if (eq (class-of gf) generic-function)
  893.       (primitive-ref gf %method-initargs)
  894.       (generic-function-method-initargs gf)))
  895.  
  896. (defun stable-add-method (gf md)
  897.   (if (and (eq (class-of gf) generic-function)
  898.        (eq (class-of md) method))
  899.       (primitive-add-method gf md)
  900.       (add-method gf md)))
  901.  
  902. ; cpl-subclass as we are talking about inheritance of behaviour
  903. (defun check-method-domain (md md-dom gf gf-dom)
  904.   (unless (and (= (length md-dom)
  905.           (length gf-dom))
  906.            (every #'cpl-subclass? md-dom gf-dom))
  907.     (error "domain mismatch in add-method:~%~s ~s" gf md)))
  908.  
  909. ; cf add-method
  910. ; cache
  911. (defun primitive-add-method (gf md)
  912.   (check-method-domain md (primitive-ref md %domain)
  913.                gf (primitive-ref gf %domain))
  914.   (let ((old (primitive-find-method gf (primitive-ref md %domain))))
  915.     (when old (primitive-remove-method gf old)))
  916.   (setf (primitive-ref gf %methods)
  917.     (cons md (primitive-ref gf %methods)))
  918.   (setf (primitive-ref md %generic-function) gf)
  919.   (setf (primitive-ref gf %cache) (reset-cache (primitive-ref gf %cache)))
  920.   gf)
  921.  
  922. (defun stable-find-method (gf domain)
  923.   (if (and (eq (class-of gf) generic-function)
  924.        (listp domain))
  925.       (primitive-find-method gf domain)
  926.       (find-method gf domain)))
  927.  
  928. ; cf find-method
  929. (defun primitive-find-method (gf sig)
  930.   (find sig (primitive-ref gf %methods)
  931.     :test #'equal
  932.     :key #'stable-method-domain))
  933.  
  934. (defun stable-remove-method (gf md)
  935.   (if (and (eq (class-of gf) generic-function)
  936.        (eq (class-of md) method))
  937.       (primitive-remove-method gf md)
  938.       (remove-method gf md)))
  939.  
  940. ; cf remove method
  941. ; cache
  942. (defun primitive-remove-method (gf md)
  943.   (let ((mds (primitive-ref gf %methods)))
  944.     (when (memq md mds)
  945.       (setf (primitive-ref gf %methods)
  946.         (remove md mds :test #'eq))
  947.       (setf (primitive-ref md %generic-function) ())
  948.       (setf (primitive-ref gf %cache)
  949.         (reset-cache (primitive-ref gf %cache)))))
  950.   gf)
  951.  
  952. (defun make-method (method-class domain fn inits)
  953.   (if (and (eq method-class method)
  954.        (listp domain)
  955.        (functionp fn)
  956.        (null inits))
  957.       (primitive-make-method domain fn)
  958.       (apply #'make
  959.          method-class
  960.          :domain domain
  961.          :function fn
  962.          inits)))
  963.  
  964. (defun primitive-make-method (domain fn)
  965.   (let ((md (primitive-allocate method method-size)))
  966.     (setf (primitive-ref md %domain) domain)
  967.     (setf (primitive-ref md %function) fn) md))
  968.  
  969. #+unrestricted-metaclass
  970. (progn
  971.  
  972. ; slot accessors
  973. (defgeneric class-name ((cl class))
  974.   :method (((cl class)) (primitive-ref cl %name)))
  975.  
  976. (defgeneric (setf class-name) ((cl class) (val symbol))
  977.   :method (((cl class) (val symbol)) (setf (primitive-ref cl %name) val)))
  978.  
  979. (defgeneric class-instance-length ((cl class))
  980.   :method (((cl class)) (primitive-ref cl %instance-length)))
  981.  
  982. (defgeneric (setf class-instance-length) ((cl class) (val integer))
  983.   :method (((cl class) (val integer))
  984.        (setf (primitive-ref cl %instance-length) val)))
  985.  
  986. (defgeneric class-direct-superclasses ((cl class))
  987.   :method (((cl class)) (primitive-ref cl %direct-superclasses)))
  988.  
  989. (defgeneric (setf class-direct-superclasses) ((cl class) (val list))
  990.   :method (((cl class) (val list))
  991.        (setf (primitive-ref cl %direct-superclasses) val)))
  992.  
  993. (defgeneric class-direct-subclasses ((cl class))
  994.   :method (((cl class)) (primitive-ref cl %direct-subclasses)))
  995.  
  996. (defgeneric (setf class-direct-subclasses) ((cl class) (val list))
  997.   :method (((cl class) (val list))
  998.        (setf (primitive-ref cl %direct-subclasses) val)))
  999.  
  1000. (defgeneric class-slot-descriptions ((cl class))
  1001.   :method (((cl class)) (primitive-ref cl %slot-descriptions)))
  1002.  
  1003. (defgeneric (setf class-slot-descriptions) ((cl class) (val list))
  1004.   :method (((cl class) (val list))
  1005.        (setf (primitive-ref cl %slot-descriptions) val)))
  1006.  
  1007. (defgeneric class-initargs ((cl class))
  1008.   :method (((cl class)) (primitive-ref cl %initargs)))
  1009.  
  1010. (defgeneric (setf class-initargs) ((cl class) (val list))
  1011.   :method (((cl class) (val list)) (setf (primitive-ref cl %initargs) val)))
  1012.  
  1013. (defgeneric class-precedence-list ((cl class))
  1014.   :method (((cl class)) (primitive-ref cl %precedence-list)))
  1015.  
  1016. (defgeneric (setf class-precedence-list) ((cl class) (val list))
  1017.   :method (((cl class) (val list))
  1018.        (setf (primitive-ref cl %precedence-list) val)))
  1019.  
  1020. (defgeneric generic-function-name ((gf generic-function))
  1021.   :method (((gf generic-function)) (primitive-ref gf %name)))
  1022.  
  1023. (defgeneric (setf generic-function-name) ((gf generic-function) (val symbol))
  1024.   :method (((gf generic-function) (val symbol))
  1025.        (setf (primitive-ref gf %name) val)))
  1026.  
  1027. (defgeneric generic-function-domain ((gf generic-function))
  1028.   :method (((gf generic-function)) (primitive-ref gf %domain)))
  1029.  
  1030. (defgeneric (setf generic-function-domain) ((gf generic-function) (val list))
  1031.   :method (((gf generic-function) (val list))
  1032.        (setf (primitive-ref gf %domain) val)))
  1033.  
  1034. (defgeneric generic-function-method-class ((gf generic-function))
  1035.   :method (((gf generic-function)) (primitive-ref gf %method-class)))
  1036.  
  1037. (defgeneric (setf generic-function-method-class)
  1038.   ((gf generic-function) (val method))
  1039.   :method (((gf generic-function) (val method))
  1040.        (setf (primitive-ref gf %method-class) val)))
  1041.  
  1042. (defgeneric generic-function-method-initargs ((gf generic-function))
  1043.   :method (((gf generic-function)) (primitive-ref gf %method-initargs)))
  1044.  
  1045. (defgeneric (setf generic-function-method-initargs)
  1046.   ((gf generic-function) (val list))
  1047.   :method (((gf generic-function) (val list))
  1048.        (setf (primitive-ref gf %method-initargs) val)))
  1049.  
  1050. (defgeneric generic-function-methods ((gf generic-function))
  1051.   :method (((gf generic-function)) (primitive-ref gf %methods)))
  1052.  
  1053. (defgeneric (setf generic-function-methods)
  1054.   ((gf generic-function) (val list))
  1055.   :method (((gf generic-function) (val list))
  1056.        (setf (primitive-ref gf %methods) val)))
  1057.  
  1058. (defgeneric generic-function-method-lookup-function ((gf generic-function))
  1059.   :method (((gf generic-function)) (primitive-ref gf %method-lookup-function)))
  1060.  
  1061. (defgeneric (setf generic-function-method-lookup-function)
  1062.   ((gf generic-function) (val function))
  1063.   :method (((gf generic-function) val)
  1064.        (setf (primitive-ref gf %method-lookup-function) val)))
  1065.  
  1066. (defgeneric generic-function-discriminating-function ((gf generic-function))
  1067.   :method (((gf generic-function))
  1068.        (primitive-ref gf %discriminating-function)))
  1069.  
  1070. (defgeneric (setf generic-function-discriminating-function)
  1071.   ((gf generic-function) (val function))
  1072.   :method (((gf generic-function) val)
  1073.        (setf (primitive-ref gf %discriminating-function) val)))
  1074.  
  1075. (defgeneric generic-function-cache ((gf generic-function))
  1076.   :method (((gf generic-function)) (primitive-ref gf %cache)))
  1077.  
  1078. (defgeneric (setf generic-function-cache) ((gf generic-function) val)
  1079.   :method (((gf generic-function) val) (setf (primitive-ref gf %cache) val)))
  1080.  
  1081. (defgeneric method-generic-function ((md method))
  1082.   :method (((md method)) (primitive-ref md %generic-function)))
  1083.  
  1084. (defgeneric (setf method-generic-function) ((md method) (val generic-function))
  1085.   :method (((md method) (val generic-function))
  1086.        (setf (primitive-ref md %generic-function) val)))
  1087.  
  1088. (defgeneric method-domain ((md method))
  1089.   :method (((md method)) (primitive-ref md %domain)))
  1090.  
  1091. (defgeneric (setf method-domain) ((md method) (val list))
  1092.   :method (((md method) (val list)) (setf (primitive-ref md %domain) val)))
  1093.  
  1094. (defgeneric method-function ((md method))
  1095.   :method (((md method)) (primitive-ref md %function)))
  1096.  
  1097. (defgeneric (setf method-function) ((md method) (val function))
  1098.   :method (((md method) val) (setf (primitive-ref md %function) val)))
  1099.  
  1100. (defgeneric slot-description-slot-reader ((sd slot-description))
  1101.   :method (((sd slot-description)) (primitive-ref sd %reader)))
  1102.  
  1103. (defgeneric (setf slot-description-slot-reader)
  1104.   ((sd slot-description) (val function))
  1105.   :method (((sd slot-description) val) (setf (primitive-ref sd %reader) val)))
  1106.  
  1107. (defgeneric slot-description-slot-writer ((sd slot-description))
  1108.   :method (((sd slot-description)) (primitive-ref sd %writer)))
  1109.  
  1110. (defgeneric (setf slot-description-slot-writer)
  1111.   ((sd slot-description) (val function))
  1112.   :method (((sd slot-description) val) (setf (primitive-ref sd %writer) val)))
  1113.  
  1114. (defgeneric slot-description-name ((sd slot-description))
  1115.   :method (((sd local-slot-description)) (primitive-ref sd %lsdname)))
  1116.  
  1117. (defgeneric (setf slot-description-name) ((sd slot-description) (val symbol))
  1118.   :method (((sd local-slot-description) (val symbol))
  1119.        (setf (primitive-ref sd %lsdname) val)))
  1120.  
  1121. (defgeneric slot-description-initfunction ((sd slot-description))
  1122.   :method (((sd local-slot-description)) (primitive-ref sd %initfunction)))
  1123.  
  1124. (defgeneric (setf slot-description-initfunction)
  1125.   ((sd slot-description) (val function))
  1126.   :method (((sd local-slot-description) val)
  1127.        (setf (primitive-ref sd %initfunction) val)))
  1128.  
  1129. (defun primitive-make-slot-description (name reader writer)
  1130.   (let ((sd (primitive-allocate local-slot-description lsd-size)))
  1131.     (setf (primitive-ref sd %lsdname) name)
  1132.     (setf (primitive-ref sd %initfunction) #'unbound)
  1133.     (setf (primitive-ref sd %reader) reader)
  1134.     (setf (primitive-ref sd %writer) writer)
  1135.     sd))
  1136.  
  1137. (defun make-slotds (names readers writers)
  1138.   (mapcar #'(lambda (name reader writer)
  1139.           (primitive-make-slot-description name reader writer))
  1140.         names readers writers))
  1141.  
  1142. ;; install the slotds ....
  1143. ;; get a macro to do this later
  1144. (let ((class-slotds (make-slotds class-slots
  1145.                  (list class-name
  1146.                        class-instance-length
  1147.                        class-direct-superclasses
  1148.                        class-direct-subclasses
  1149.                        class-slot-descriptions
  1150.                        class-initargs
  1151.                        class-precedence-list)
  1152.                  (list setter-class-name
  1153.                        setter-class-instance-length
  1154.                        setter-class-direct-superclasses
  1155.                        setter-class-direct-subclasses
  1156.                        setter-class-slot-descriptions
  1157.                        setter-class-initargs
  1158.                        setter-class-precedence-list))))
  1159.   (setf (primitive-ref class %slot-descriptions) class-slotds)
  1160.   (setf (primitive-ref metaclass %slot-descriptions) class-slotds)
  1161.   (setf (primitive-ref abstract-class %slot-descriptions) class-slotds)
  1162.   (setf (primitive-ref function-class %slot-descriptions) class-slotds)
  1163.   (setf (primitive-ref common %slot-descriptions) class-slotds))
  1164.  
  1165. (setf (primitive-ref generic-function %slot-descriptions)
  1166.       (make-slotds gf-slots
  1167.            (list generic-function-name
  1168.              generic-function-domain
  1169.              generic-function-method-class
  1170.              generic-function-method-initargs
  1171.              generic-function-methods
  1172.              generic-function-method-lookup-function
  1173.              generic-function-discriminating-function
  1174.              generic-function-cache)
  1175.            (list setter-generic-function-name
  1176.              setter-generic-function-domain
  1177.                          setter-generic-function-method-class
  1178.              setter-generic-function-method-initargs
  1179.                          setter-generic-function-methods
  1180.                          setter-generic-function-method-lookup-function
  1181.                          setter-generic-function-discriminating-function
  1182.                          setter-generic-function-cache)))
  1183.  
  1184. (setf (primitive-ref method %slot-descriptions)
  1185.       (make-slotds method-slots
  1186.            (list method-generic-function
  1187.              method-domain
  1188.              method-function)
  1189.            (list setter-method-generic-function
  1190.              setter-method-domain
  1191.              setter-method-function)))
  1192.  
  1193. (let ((sd-slotds (make-slotds lsd-slots
  1194.                   (list slot-description-slot-reader
  1195.                     slot-description-slot-writer
  1196.                     slot-description-name
  1197.                     slot-description-initfunction)
  1198.                   (list setter-slot-description-slot-reader
  1199.                     setter-slot-description-slot-writer
  1200.                     setter-slot-description-name
  1201.                     setter-slot-description-initfunction))))
  1202.   (setf (primitive-ref slot-description %slot-descriptions)
  1203.     (list (car sd-slotds) (cadr sd-slotds)))
  1204.   (setf (primitive-ref local-slot-description %slot-descriptions) sd-slotds))
  1205.  
  1206. ()
  1207.  
  1208. ) ; end #+unrestricted-metaclass
  1209.  
  1210. #-unrestricted-metaclass
  1211. (progn
  1212.  
  1213. (defun class-name (cl) (primitive-ref cl %name))
  1214. (defun setter-class-name (cl val) (setf (primitive-ref cl %name) val))
  1215. (defsetf class-name setter-class-name)
  1216.  
  1217. (defun class-instance-length (cl) (primitive-ref cl %instance-length))
  1218. (defun setter-class-instance-length (cl val)
  1219.   (setf (primitive-ref cl %instance-length) val))
  1220. (defsetf class-instance-length setter-class-instance-length)
  1221.  
  1222. (defun class-direct-superclasses (cl) (primitive-ref cl %direct-superclasses))
  1223. (defun setter-class-direct-superclasses (cl val)
  1224.   (setf (primitive-ref cl %direct-superclasses) val))
  1225. (defsetf class-direct-superclasses setter-class-direct-superclasses)
  1226.  
  1227. (defun class-direct-subclasses (cl) (primitive-ref cl %direct-subclasses))
  1228. (defun setter-class-direct-subclasses (cl val)
  1229.   (setf (primitive-ref cl %direct-subclasses) val))
  1230. (defsetf class-direct-subclasses setter-class-direct-subclasses)
  1231.  
  1232. (defun class-slot-descriptions (cl) (primitive-ref cl %slot-descriptions))
  1233. (defun setter-class-slot-descriptions (cl val)
  1234.   (setf (primitive-ref cl %slot-descriptions) val))
  1235. (defsetf class-slot-descriptions setter-class-slot-descriptions)
  1236.  
  1237. (defun class-initargs (cl) (primitive-ref cl %initargs))
  1238. (defun setter-class-initargs (cl val)
  1239.   (setf (primitive-ref cl %initargs) val))
  1240. (defsetf class-initargs setter-class-initargs)
  1241.  
  1242. (defun class-precedence-list (cl) (primitive-ref cl %precedence-list))
  1243. (defun setter-class-precedence-list (cl val)
  1244.   (setf (primitive-ref cl %precedence-list) val))
  1245. (defsetf class-precedence-list setter-class-precedence-list)
  1246.  
  1247. (defun generic-function-name (gf) (primitive-ref gf %name))
  1248. (defun setter-generic-function-name (gf val)
  1249.   (setf (primitive-ref gf %name) val))
  1250. (defsetf generic-function-name setter-generic-function-name)
  1251.  
  1252. (defun generic-function-domain (gf) (primitive-ref gf %domain))
  1253. (defun setter-generic-function-domain (gf val)
  1254.   (setf (primitive-ref gf %domain) val))
  1255. (defsetf generic-function-domain setter-generic-function-domain)
  1256.  
  1257. (defun generic-function-method-class (gf) (primitive-ref gf %method-class))
  1258. (defun setter-generic-function-method-class (gf val)
  1259.   (setf (primitive-ref gf %method-class) val))
  1260. (defsetf generic-function-method-class setter-generic-function-method-class)
  1261.  
  1262. (defun generic-function-method-initargs (gf)
  1263.   (primitive-ref gf %method-initargs))
  1264. (defun setter-generic-function-method-initargs (gf val)
  1265.   (setf (primitive-ref gf %method-initargs) val))
  1266. (defsetf generic-function-method-initargs
  1267.   setter-generic-function-method-initargs)
  1268.  
  1269. (defun generic-function-methods (gf) (primitive-ref gf %methods))
  1270. (defun setter-generic-function-methods (gf val)
  1271.   (setf (primitive-ref gf %methods) val))
  1272. (defsetf generic-function-methods setter-generic-function-methods)
  1273.  
  1274. (defun generic-function-method-lookup-function (gf)
  1275.   (primitive-ref gf %method-lookup-function))
  1276. (defun setter-generic-function-method-lookup-function (gf val)
  1277.   (setf (primitive-ref gf %method-lookup-function) val))
  1278. (defsetf generic-function-method-lookup-function
  1279.   setter-generic-function-method-lookup-function)
  1280.  
  1281. (defun generic-function-discriminating-function (gf)
  1282.   (primitive-ref gf %discriminating-function))
  1283. (defun setter-generic-function-discriminating-function (gf val)
  1284.   (setf (primitive-ref gf %discriminating-function) val))
  1285. (defsetf generic-function-discriminating-function
  1286.   setter-generic-function-discriminating-function)
  1287.  
  1288. (defun generic-function-cache (gf) (primitive-ref gf %cache))
  1289. (defun setter-generic-function-cache (gf val)
  1290.   (setf (primitive-ref gf %cache) val))
  1291. (defsetf generic-function-cache setter-generic-function-cache)
  1292.  
  1293. (defun method-generic-function (md) (primitive-ref md %generic-function))
  1294. (defun setter-method-generic-function (md val)
  1295.   (setf (primitive-ref md %generic-function) val))
  1296. (defsetf method-generic-function setter-method-generic-function)
  1297.  
  1298. (defun method-domain (md) (primitive-ref md %domain))
  1299. (defun setter-method-domain (md val)
  1300.   (setf (primitive-ref md %domain) val))
  1301. (defsetf method-domain setter-method-domain)
  1302.  
  1303. (defun method-function (md) (primitive-ref md %function))
  1304. (defun setter-method-function (md val)
  1305.   (setf (primitive-ref md %function) val))
  1306. (defsetf method-function setter-method-function)
  1307.  
  1308. (defun slot-description-slot-reader (sd) (primitive-ref sd %reader))
  1309. (defun setter-slot-description-slot-reader (sd val)
  1310.   (setf (primitive-ref sd %reader) val))
  1311. (defsetf slot-description-slot-reader setter-slot-description-slot-reader)
  1312.  
  1313. (defun slot-description-slot-writer (sd) (primitive-ref sd %writer))
  1314. (defun setter-slot-description-slot-writer (sd val)
  1315.   (setf (primitive-ref sd %writer) val))
  1316. (defsetf slot-description-slot-writer setter-slot-description-slot-writer)
  1317.  
  1318. (defun slot-description-name (sd) (primitive-ref sd %lsdname))
  1319. (defun setter-slot-description-name (sd val)
  1320.   (setf (primitive-ref sd %lsdname) val))
  1321. (defsetf slot-description-name setter-slot-description-name)
  1322.  
  1323. (defun slot-description-initfunction (sd) (primitive-ref sd %initfunction))
  1324. (defun setter-slot-description-initfunction (sd val)
  1325.   (setf (primitive-ref sd %initfunction) val))
  1326. (defsetf slot-description-initfunction setter-slot-description-initfunction)
  1327.  
  1328. (defun primitive-make-slot-description (name index class)
  1329.   (let ((sd (primitive-allocate local-slot-description lsd-size)))
  1330.     (setf (primitive-ref sd %lsdname) name)
  1331.     (setf (primitive-ref sd %initfunction) #'unbound)
  1332.     (let ((reader (primitive-make-generic-function
  1333.            (construct-name "~a-~a" (primitive-ref class %name) name)
  1334.            (list class))))
  1335.       (stable-add-method reader
  1336.              (primitive-make-method
  1337.               (list class)
  1338.               (method-function-lambda (obj)
  1339.                  (primitive-ref obj index))))
  1340.     (setf (primitive-ref sd %reader) reader))
  1341.     (let ((writer (primitive-make-generic-function
  1342.            (construct-name "SETTER-~a-~a"
  1343.                    (primitive-ref class %name)
  1344.                    name)
  1345.            (list class object))))
  1346.       (stable-add-method writer
  1347.              (primitive-make-method
  1348.               (list class object)
  1349.               (method-function-lambda (obj val)
  1350.                 (setf (primitive-ref obj index) val))))
  1351.       (setf (primitive-ref sd %writer) writer))
  1352.     sd))
  1353.  
  1354. (defun make-slotds (names index class)
  1355.   (if (null names)
  1356.       ()
  1357.       (cons (primitive-make-slot-description (car names) index class)
  1358.         (make-slotds (cdr names) (+ index 1) class))))
  1359.  
  1360. (let ((class-slotds (make-slotds class-slots 0 class)))
  1361.   (setf (primitive-ref class %slot-descriptions) class-slotds)
  1362.   (setf (primitive-ref metaclass %slot-descriptions) class-slotds)
  1363.   (setf (primitive-ref abstract-class %slot-descriptions) class-slotds)
  1364.   (setf (primitive-ref function-class %slot-descriptions) class-slotds)
  1365.   (setf (primitive-ref common %slot-descriptions) class-slotds))
  1366.  
  1367. (setf (primitive-ref generic-function %slot-descriptions)
  1368.       (make-slotds gf-slots 0 generic-function))
  1369.  
  1370. (setf (primitive-ref method %slot-descriptions)
  1371.       (make-slotds method-slots 0 method))
  1372.  
  1373. (let ((sd-slotds (make-slotds lsd-slots 0 slot-description)))
  1374.   (setf (primitive-ref slot-description %slot-descriptions)
  1375.     (list (car sd-slotds) (cadr sd-slotds)))
  1376.   (setf (primitive-ref local-slot-description %slot-descriptions) sd-slotds))
  1377.  
  1378. ()
  1379.  
  1380. ) ; end #-unrestricted-metaclass
  1381.  
  1382. ; more useful accessors
  1383. (defgeneric slot-value-using-slot-description ((sd slot-description) obj)
  1384.   :method (((sd slot-description) obj)
  1385.        (generic-funcall (slot-description-slot-reader sd) obj)))
  1386.  
  1387. (defgeneric (setf slot-value-using-slot-description)
  1388.   ((sd slot-description) obj val)
  1389.   :method (((sd slot-description) obj val)
  1390.        (generic-funcall (slot-description-slot-writer sd) obj val)))
  1391.  
  1392. (eval-when (compile)
  1393.   (defsetf slot-value-using-slot-description
  1394.     setter-slot-value-using-slot-description))
  1395.  
  1396. (defgeneric find-slot-description ((cl class) (symb symbol)))
  1397.  
  1398. (defmethod find-slot-description ((cl class) (symb symbol))
  1399.   (let ((sd (find (key2symbol symb)
  1400.           (class-slot-descriptions cl)
  1401.           :test #'eq
  1402.           :key #'slot-description-name)))
  1403.     (if (null sd)
  1404.     (error "slot ~s not found in class ~s" symb cl)
  1405.     sd)))
  1406.  
  1407. (defun slot-value (obj name)
  1408.   (if (primitive-metaclass? (class-of (class-of obj)))
  1409.       (primitive-slot-value obj name)
  1410.       (slot-value-using-slot-description
  1411.        (find-slot-description (class-of obj) name)
  1412.        obj)))
  1413.  
  1414. (defun setter-slot-value (obj name val)
  1415.   (if (primitive-metaclass? (class-of (class-of obj)))
  1416.       (setf (primitive-slot-value obj name) val)
  1417.       (setf (slot-value-using-slot-description
  1418.          (find-slot-description (class-of obj) name)
  1419.          obj)
  1420.         val)))
  1421.  
  1422. (defsetf slot-value setter-slot-value)
  1423.  
  1424. ;;;--------------------------------------------------------------------
  1425. ;;;
  1426. ;;; the MOP proper starts here
  1427. ;;;
  1428. (defun make (cl &rest initargs)
  1429.   (initialize (allocate cl initargs) initargs))
  1430.  
  1431. (defgeneric allocate ((cl class) inits))
  1432.  
  1433. (defmethod allocate ((cl abstract-class) (inits list))
  1434.   (declare (ignore inits))
  1435.   (error "can't allocate an instance of an abstract-class ~s") cl)
  1436.  
  1437. (defmethod allocate ((cl class) (inits list))
  1438.   (declare (ignore inits))
  1439.   (primitive-allocate cl (class-instance-length cl)))
  1440.  
  1441. (defun check-legal-initargs (cl initargs)
  1442.   (let ((objinits (class-initargs cl)))
  1443.     (labels ((legal-initargs? (inits)
  1444.                (cond ((null inits) t)
  1445.                      ((memq (car inits) objinits)
  1446.                       (legal-initargs? (cddr inits)))
  1447.                      (t
  1448.                       (error "illegal initarg ~s in initialization of class ~a"
  1449.                  (car inits) cl)))))
  1450.       (legal-initargs? initargs))))
  1451.  
  1452. (defgeneric initialize ((obj object) initargs))
  1453.  
  1454. (defmethod initialize ((obj object) (initargs list))
  1455.   (let ((cl (class-of obj)))
  1456.     (check-legal-initargs cl initargs)
  1457.     (mapc #'(lambda (sd)
  1458.           (initialize-using-slot-description obj sd initargs))
  1459.       (class-slot-descriptions cl)))
  1460.   obj)
  1461.  
  1462. (defgeneric initialize-using-slot-description
  1463.   ((obj object) (sd slot-description) initargs))
  1464.  
  1465. (defmethod initialize-using-slot-description
  1466.   ((obj object) (sd local-slot-description) (initargs list))
  1467.   (let ((val (find-key (slot-description-name sd)
  1468.                initargs
  1469.                unbound)))
  1470.     (setf (slot-value-using-slot-description sd obj)
  1471.       (if (eq val unbound)
  1472.           (generic-funcall
  1473.            (slot-description-initfunction sd))
  1474.           val)))
  1475.   obj)
  1476.  
  1477. ; relies on name capture
  1478. ; c-n-m
  1479. (defmacro call-next-method ()
  1480.   `(if (null *method-list*)
  1481.        (error "no next method")
  1482.        (apply-method (car *method-list*)
  1483.              (cdr *method-list*)
  1484.              *argument-list*)))
  1485.  
  1486. ; c-n-m
  1487. (defmacro next-method? ()
  1488.   `(not (null *method-list*)))
  1489.  
  1490. ; c-n-m
  1491. (defun apply-method (md next-mds args)
  1492.   (apply (method-function md) next-mds args args))
  1493.  
  1494. ; c-n-m
  1495. (defun call-method (md next-mds &rest args)
  1496.   (apply (method-function md) next-mds args args))
  1497.  
  1498. (defmethod initialize ((gf generic-function) (initargs list))
  1499.   (let ((name (find-key :name initargs :anonymous))
  1500.     (domain (find-key :domain initargs required))
  1501.     (method-class (find-key :method-class initargs method))
  1502.     (method-inits (find-key :method-initargs initargs ()))
  1503.     (methods (find-key :methods initargs ())))
  1504.     (call-next-method)
  1505.     (setf (generic-function-name gf) name)
  1506.     (setf (generic-function-method-class gf) method-class)
  1507.     (setf (generic-function-method-initargs gf) method-inits)
  1508.     (setf (generic-function-methods gf) ())
  1509.     (setf (generic-function-cache gf) (new-cache))
  1510.     (let ((lookup-fn (compute-method-lookup-function gf domain)))
  1511.       (setf (generic-function-method-lookup-function gf) lookup-fn)
  1512.       (setf (generic-function-discriminating-function gf)
  1513.         (compute-discriminating-function gf domain lookup-fn ())))
  1514.     (mapc #'(lambda (md) (add-method gf md)) methods))
  1515.   gf)
  1516.  
  1517. ; takes same args as the gf
  1518. (defgeneric compute-method-lookup-function ((gf generic-function) (sig list))
  1519.   :method (((gf generic-function) (sig cons))
  1520.            (declare (ignore sig))
  1521.        (let ((nargs (length (generic-function-domain gf))))
  1522.          #'(lambda (&rest values)
  1523.          (the-method-lookup-function
  1524.           gf
  1525.           (required-domain values nargs))))))
  1526.  
  1527. (defgeneric compute-discriminating-function
  1528.   ((gf generic-function) (domain list) (lookup-fn function) (meths list)))
  1529.  
  1530. ; cache
  1531. ; cf compute-primitive-discriminating-function
  1532. ; takes same args as the gf
  1533. (defmethod compute-discriminating-function
  1534.   ((gf generic-function) (domain cons) (lookup-fn function) (meths null))
  1535.   (declare (ignore domain meths))
  1536.   (let ((cache (generic-function-cache gf))
  1537.     (nargs (length (generic-function-domain gf))))
  1538.     #'(lambda (&rest values)
  1539.     (check-nargs gf (length values) nargs)
  1540.     (let ((applicable (cache-lookup
  1541.                values
  1542.                (required-domain values nargs)
  1543.                cache
  1544.                lookup-fn)))
  1545.       (if (null applicable)
  1546.           (error "no applicable methods ~s:~%arguments:~%~s~%classes:~%~s"
  1547.              gf
  1548.              values
  1549.              (mapcar #'class-of values))
  1550.           (apply (car applicable)    ; apply-method
  1551.              (cdr applicable)
  1552.              values
  1553.              values))))))
  1554.  
  1555. (defmethod initialize ((md method) (initargs list))
  1556.   (let ((domain (find-key :domain initargs required))
  1557.         (fn (find-key :function initargs required))
  1558.     (gf (find-key :generic-function initargs ())))
  1559.     (declare (ignore domain fn))
  1560.     (call-next-method)
  1561.     (unless (null gf) (add-method gf md)) ; make sure the gf knows what's up
  1562.     md))
  1563.  
  1564. (defgeneric add-method ((gf generic-function) (md method)))
  1565.  
  1566. ; cf primitive-add-method
  1567. ; cache
  1568. (defmethod add-method ((gf generic-function) (md method))
  1569.   (check-method-domain md (method-domain md)
  1570.                gf (generic-function-domain gf))
  1571.   (unless (subclass? (class-of md)
  1572.              (generic-function-method-class gf))
  1573.     (error "method class mismatch in add-method:~%~s ~s" gf (class-of md)))
  1574.   (let ((old (find-method gf (method-domain md))))
  1575.     (when old (remove-method gf old)))
  1576.   (setf (generic-function-methods gf)
  1577.     (cons md (generic-function-methods gf)))
  1578.   (setf (method-generic-function md) gf)
  1579.   (setf (generic-function-cache gf) (reset-cache (generic-function-cache gf)))
  1580.   gf)
  1581.  
  1582. (defgeneric find-method ((gf generic-function) (sig list)))
  1583.  
  1584. ; cf primitive-find-method
  1585. (defmethod find-method ((gf generic-function) (sig cons))
  1586.   (find sig (generic-function-methods gf)
  1587.     :test #'equal
  1588.     :key #'method-domain))
  1589.  
  1590. (defgeneric remove-method ((gf generic-function) (md method)))
  1591.  
  1592. ; cf primitive-remove-method
  1593. ; cache
  1594. (defmethod remove-method ((gf generic-function) (md method))
  1595.   (let ((mds (generic-function-methods gf)))
  1596.     (when (memq md mds)
  1597.       (setf (generic-function-methods gf)
  1598.             (remove md mds :test #'eq))
  1599.       (setf (method-generic-function md) ())
  1600.       (setf (generic-function-cache gf)
  1601.         (reset-cache (generic-function-cache gf)))))
  1602.   gf)
  1603.  
  1604. (defmethod initialize ((sd local-slot-description) (initargs list))
  1605.   (find-key :name initargs required)
  1606.   (call-next-method)
  1607.   (setf (slot-description-initfunction sd)
  1608.     (find-key :initfunction initargs #'unbound))
  1609.   sd)
  1610.  
  1611. (defmethod initialize ((cl class) (initargs list))
  1612.   (let ((name
  1613.      (find-key :name initargs :anonymous))
  1614.     (direct-supers
  1615.      (find-key :direct-superclasses initargs (list object)))
  1616.     (direct-slotds
  1617.      (find-key :direct-slot-descriptions initargs ()))
  1618.     (direct-inits
  1619.      (find-key :direct-initargs initargs ())))
  1620.     (call-next-method)
  1621.     (setf (class-name cl) name)
  1622.     (setf (class-direct-superclasses cl) direct-supers)
  1623.     (setf (class-direct-subclasses cl) ())
  1624.     (unless (compatible-superclasses-p cl direct-supers)
  1625.       (error "incompatible superclasses:~%~s can not be a subclass of ~%~s"
  1626.          cl direct-supers))
  1627.     (let ((cpl (compute-class-precedence-list cl direct-supers)))
  1628.       (setf (class-precedence-list cl) cpl)
  1629.       (let ((effective-inits (compute-initargs
  1630.                   cl direct-inits
  1631.                   (compute-inherited-initargs cl direct-supers))))
  1632.     (setf (class-initargs cl) effective-inits)
  1633.     (let ((inherited-slotds (compute-inherited-slot-descriptions
  1634.                  cl direct-supers)))
  1635.       (let ((effective-slotds
  1636.          (compute-and-ensure-slot-accessors
  1637.           cl (compute-slot-descriptions
  1638.               cl direct-slotds inherited-slotds)
  1639.           inherited-slotds)))
  1640.         (setf (class-slot-descriptions cl) effective-slotds)
  1641.         (setf (class-instance-length cl) (length effective-slotds))
  1642.         (mapcar #'(lambda (super)
  1643.             (add-subclass super cl)) direct-supers))))))
  1644.   cl)
  1645.  
  1646. (defgeneric compatible-superclasses-p ((cl class) (superclasses list)))
  1647.   
  1648. ; si
  1649. (defmethod compatible-superclasses-p ((cl class) (superclasses cons))
  1650.   (compatible-superclass-p cl (car superclasses)))
  1651.  
  1652. (defgeneric compatible-superclass-p ((cl class) (superclass class)))
  1653.  
  1654. #+unrestricted-metaclass
  1655. (defmethod compatible-superclass-p ((cl class) (super class))
  1656.   (subclass? (class-of cl) (class-of super)))
  1657.  
  1658. #-unrestricted-metaclass
  1659. (defmethod compatible-superclass-p ((cl class) (super class))
  1660.   (if (eq super metaclass)
  1661.       ()
  1662.       (subclass? (class-of cl) (class-of super))))
  1663.  
  1664. (defmethod compatible-superclass-p ((cl class) (super abstract-class))
  1665.   (declare (ignore cl super))
  1666.   t)
  1667.  
  1668. ; patchy here
  1669. (defmethod compatible-superclass-p ((cl abstract-class) (super class))
  1670.   (declare (ignore cl super))
  1671.   ())
  1672.  
  1673. ; patchy here
  1674. (defmethod compatible-superclass-p ((cl abstract-class) (super abstract-class))
  1675.   (declare (ignore cl super))
  1676.   t)
  1677.  
  1678. (defgeneric compute-class-precedence-list ((cl class) (direct-supers list)))
  1679.  
  1680. ; si
  1681. (defmethod compute-class-precedence-list ((cl class) (direct-supers cons))
  1682.   (cons cl (class-precedence-list (car direct-supers))))
  1683.  
  1684. (defgeneric compute-inherited-initargs ((cl class) (direct-supers list)))
  1685.  
  1686. ; si
  1687. (defmethod compute-inherited-initargs ((cl class) (direct-supers cons))
  1688.   (declare (ignore cl))
  1689.   (list (class-initargs (car direct-supers))))
  1690.  
  1691. (defgeneric compute-initargs
  1692.   ((cl class) (direct-inits list) (inherited-inits list)))
  1693.  
  1694. ; si
  1695. (defmethod compute-initargs
  1696.   ((cl class) (direct-inits list) (inherited-inits cons))
  1697.   (declare (ignore cl))
  1698.   (remove-duplicates (append direct-inits (car inherited-inits))
  1699.              :test #'eq))
  1700.  
  1701. (defgeneric compute-inherited-slot-descriptions
  1702.   ((cl class) (direct-supers list)))
  1703.  
  1704. ; si
  1705. (defmethod compute-inherited-slot-descriptions
  1706.   ((cl class) (direct-supers cons))
  1707.   (declare (ignore cl))
  1708.   (list (class-slot-descriptions (car direct-supers))))
  1709.  
  1710. (defgeneric compute-slot-descriptions
  1711.   ((cl class) (slotd-specs list) (inherited-slotds list)))
  1712.  
  1713. ; si
  1714. (defmethod compute-slot-descriptions
  1715.   ((cl class) (slotd-specs list) (inherited-slotds cons))
  1716.   (let ((old-sd-names (mapcar #'slot-description-name (car inherited-slotds)))
  1717.     (new-sd-plist (mapcan #'(lambda (spec)
  1718.                   (list (find-key :name spec required)
  1719.                     spec))
  1720.                   slotd-specs)))
  1721.     (append
  1722.      (mapcar #'(lambda (sd)
  1723.              (compute-specialized-slot-description
  1724.               cl (list sd)
  1725.               (getf new-sd-plist (slot-description-name sd))))
  1726.          (car inherited-slotds))
  1727.      (mapcan #'(lambda (spec)
  1728.              (if (memq (find-key :name spec required) old-sd-names)
  1729.              ()
  1730.              (list (compute-defined-slot-description
  1731.                 cl spec))))
  1732.          slotd-specs))))
  1733.  
  1734. (defgeneric compute-specialized-slot-description
  1735.   ((cl class) (sds list) (spec list)))
  1736.  
  1737. ; si
  1738. (defmethod compute-specialized-slot-description
  1739.   ((cl class) (sds cons) (spec null))
  1740.   (let ((sd (car sds))
  1741.     (sdclass (compute-specialized-slot-description-class cl sds spec)))
  1742.     (if (eq sdclass (class-of sd))
  1743.     sd
  1744.     (make sdclass            ; what of other initargs?
  1745.           :name (slot-description-name sd)
  1746.           :initfunction (slot-description-initfunction sd)
  1747.           :reader (slot-description-slot-reader sd)
  1748.           :writer (slot-description-slot-writer sd)))))
  1749.  
  1750. ; si
  1751. (defmethod compute-specialized-slot-description
  1752.   ((cl class) (sds cons) (spec cons))
  1753.   (apply #'make
  1754.      (compute-specialized-slot-description-class cl sds spec)
  1755.      spec))
  1756.  
  1757. (defgeneric compute-specialized-slot-description-class
  1758.   ((cl class) (sds list) (spec list)))
  1759.  
  1760. (defmethod compute-specialized-slot-description-class
  1761.   ((cl class) (sds cons) (spec list))
  1762.   (declare (ignore cl sds spec))
  1763.   local-slot-description)
  1764.  
  1765. (defgeneric compute-defined-slot-description ((cl class) (spec list)))
  1766.  
  1767. (defmethod compute-defined-slot-description ((cl class) (spec cons))
  1768.   (apply #'make
  1769.      (compute-defined-slot-description-class cl spec)
  1770.      spec))
  1771.  
  1772. (defgeneric compute-defined-slot-description-class ((cl class) (spec list)))
  1773.  
  1774. (defmethod compute-defined-slot-description-class ((cl class) (spec cons))
  1775.   (declare (ignore cl spec))
  1776.   local-slot-description)
  1777.  
  1778. (defgeneric copy-object (obj))
  1779.  
  1780. (defmethod copy-object (obj)
  1781.   (let* ((cl (class-of obj))
  1782.      (new (allocate cl ())))
  1783.     (mapc #'(lambda (sd)
  1784.           (setf (slot-value-using-slot-description sd new)
  1785.             (slot-value-using-slot-description sd obj)))
  1786.       (class-slot-descriptions cl))
  1787.     new))
  1788.  
  1789. (defgeneric compute-and-ensure-slot-accessors
  1790.   ((cl class) (effective-slotds list) (inherited-slotds list)))
  1791.  
  1792. ; si
  1793. ; if inheriting a sd, assume its reader & writer are OK
  1794. (defmethod compute-and-ensure-slot-accessors
  1795.   ((cl class) (effective-slotds list) (inherited-slotds cons))
  1796.   (mapc #'(lambda (sd)
  1797.         (unless (memq sd (car inherited-slotds))
  1798.           (let ((reader (compute-slot-reader cl sd effective-slotds))
  1799.             (writer (compute-slot-writer cl sd effective-slotds)))
  1800.         (setf (slot-description-slot-reader sd) reader)
  1801.         (setf (slot-description-slot-writer sd) writer)))
  1802.         (ensure-slot-reader cl sd effective-slotds
  1803.                 (slot-description-slot-reader sd))
  1804.         (ensure-slot-writer cl sd effective-slotds
  1805.                 (slot-description-slot-writer sd)))
  1806.     effective-slotds)
  1807.   effective-slotds)
  1808.  
  1809. (defgeneric compute-slot-reader
  1810.   ((cl class) (slotd slot-description) (effective-slotds list)))
  1811.  
  1812. (defmethod compute-slot-reader
  1813.   ((cl class) (slotd slot-description) (effective-slotds list))
  1814.   (declare (ignore slotd effective-slotds))
  1815.   (make generic-function
  1816.     :domain (list cl)
  1817.     :method-class method))
  1818.  
  1819. (defmethod compute-slot-reader
  1820.   ((cl class) (slotd local-slot-description) (effective-slotds list))
  1821.   (declare (ignore effective-slotds))
  1822.   (make generic-function
  1823.         :name (construct-name "~a-~a"
  1824.                               (class-name cl)
  1825.                               (slot-description-name slotd))
  1826.         :domain (list cl)
  1827.         :method-class method))
  1828.  
  1829. (defgeneric compute-slot-writer
  1830.   ((cl class) (slotd slot-description) (effective-slotds list)))
  1831.  
  1832. (defmethod compute-slot-writer
  1833.   ((cl class) (slotd slot-description) (effective-slotds list))
  1834.   (declare (ignore slotd effective-slotds))
  1835.   (make generic-function
  1836.     :domain (list cl object)
  1837.     :method-class method))
  1838.  
  1839. (defmethod compute-slot-writer
  1840.   ((cl class) (slotd local-slot-description) (effective-slotds list))
  1841.   (declare (ignore effective-slotds))
  1842.   (make generic-function
  1843.     :name (construct-name "SETTER-~a-~a"
  1844.                   (class-name cl)
  1845.                   (slot-description-name slotd))
  1846.     :domain (list cl object)
  1847.     :method-class method))
  1848.  
  1849. (defgeneric ensure-slot-reader
  1850.   ((cl class) (slotd slot-description)
  1851.    (effective-slotds list) (reader generic-function)))
  1852.  
  1853. ; if there is a method, assume it's OK
  1854. (defmethod ensure-slot-reader
  1855.   ((cl class) (slotd slot-description)
  1856.    (effective-slotds list) (reader generic-function))
  1857.   (when (null (generic-function-methods reader))
  1858.     (let ((primitive-reader
  1859.        (compute-primitive-reader-using-slot-description
  1860.         slotd cl effective-slotds)))
  1861.       (add-method reader
  1862.           (make (generic-function-method-class reader)
  1863.             :domain (list cl)
  1864.             :function (method-function-lambda (obj)
  1865.                     (funcall primitive-reader obj))))))
  1866.   reader)
  1867.  
  1868. (defgeneric compute-primitive-reader-using-slot-description
  1869.   ((slotd slot-description) (cl class) (effective-slotds list)))
  1870.  
  1871. (defmethod compute-primitive-reader-using-slot-description
  1872.   ((slotd slot-description) (cl class) (effective-slotds list))
  1873.   (compute-primitive-reader-using-class cl slotd effective-slotds))
  1874.  
  1875. (defgeneric compute-primitive-reader-using-class
  1876.   ((cl class) (slotd slot-description) (effective-slotds list)))
  1877.  
  1878. ; search on readers rather than names
  1879. (defmethod compute-primitive-reader-using-class
  1880.   ((cl class) (slotd slot-description) (effective-slotds cons))
  1881.   (declare (ignore cl))
  1882.   (let ((reader (slot-description-slot-reader slotd)))
  1883.     (labels ((count (n slots)
  1884.            (if (eq reader (slot-description-slot-reader (car slots)))
  1885.            n
  1886.            (count (+ n 1) (cdr slots)))))
  1887.       (let ((index (count 0 effective-slotds)))
  1888.     #'(lambda (sd)
  1889.         (primitive-ref sd index))))))
  1890.  
  1891. (defgeneric ensure-slot-writer
  1892.   ((cl class) (slotd slot-description)
  1893.    (effective-slotds list) (writer generic-function)))
  1894.  
  1895. ; if there is a method, assume it's OK
  1896. (defmethod ensure-slot-writer
  1897.   ((cl class) (slotd slot-description)
  1898.    (effective-slotds list) (writer generic-function))
  1899.   (when (null (generic-function-methods writer))
  1900.     (let ((primitive-writer
  1901.        (compute-primitive-writer-using-slot-description
  1902.         slotd cl effective-slotds)))
  1903.       (add-method writer
  1904.           (make (generic-function-method-class writer)
  1905.             :domain (list cl object)
  1906.             :function (method-function-lambda (obj val)
  1907.                     (funcall primitive-writer obj val))))))
  1908.   writer)
  1909.  
  1910. (defgeneric compute-primitive-writer-using-slot-description
  1911.   ((slotd slot-description) (cl class) (effective-slotds list)))
  1912.  
  1913. (defmethod compute-primitive-writer-using-slot-description
  1914.   ((slotd slot-description) (cl class) (effective-slotds list))
  1915.   (compute-primitive-writer-using-class cl slotd effective-slotds))
  1916.   
  1917. (defgeneric compute-primitive-writer-using-class
  1918.   ((cl class) (slotd slot-description) (effective-slotds list)))
  1919.  
  1920. (defmethod compute-primitive-writer-using-class
  1921.   ((cl class) (slotd slot-description) (effective-slotds cons))
  1922.   (declare (ignore cl))
  1923.   (let ((reader (slot-description-slot-reader slotd)))
  1924.     (labels ((count (n slots)
  1925.            (if (eq reader (slot-description-slot-reader (car slots)))
  1926.                    n
  1927.                    (count (+ n 1) (cdr slots)))))
  1928.       (let ((index (count 0 effective-slotds)))
  1929.         #'(lambda (sd val)
  1930.         (setf (primitive-ref sd index) val))))))
  1931.  
  1932. (defgeneric add-subclass ((super class) (sub class)))
  1933.  
  1934. ; would be nice to have weak pointers here
  1935. (defmethod add-subclass ((super class) (sub class))
  1936.   (setf (class-direct-subclasses super)
  1937.     (cons sub (class-direct-subclasses super))))
  1938.  
  1939. (eval-when (compile load eval)
  1940.  
  1941. (defun do-direct-slotds (slots)
  1942.   (cond ((null slots) ())
  1943.     ((atom (car slots))
  1944.      (cons `(list :name ',(car slots)
  1945.               :initfunction #'unbound)
  1946.            (do-direct-slotds (cdr slots))))
  1947.     (t (cons `(list :name ',(caar slots)
  1948.             ,@(let ((initf (find-key :initform
  1949.                          (cdar slots)
  1950.                          ())))
  1951.                 (if (null initf)
  1952.                 ()
  1953.                 `(:initfunction
  1954.                   #'(lambda () ,initf))))
  1955.             ,@(filter-initargs (cdar slots)
  1956.                        '(:initform :accessor
  1957.                                :reader :writer)))
  1958.          (do-direct-slotds (cdr slots))))))
  1959.  
  1960. (defun do-accessors (name slots)
  1961.   (mapcan #'(lambda (s)
  1962.           (if (atom s)
  1963.           ()
  1964.           (do-accessor name (car s) (cdr s))))
  1965.       slots))
  1966.  
  1967. (defun do-accessor (name slotname inits)
  1968.   (cond ((null inits) ())
  1969.     ((eq (car inits) :accessor)
  1970.      (let ((acc (cadr inits))
  1971.            (setter (reader2writer (cadr inits))))
  1972.        (append (do-reader acc name slotname)
  1973.            (do-writer setter name slotname)
  1974.            `((defsetf ,acc ,setter))
  1975.            (do-accessor name slotname (cddr inits)))))
  1976.     ((eq (car inits) :reader)
  1977.      (let ((acc (cadr inits)))
  1978.        (append (do-reader acc name slotname)
  1979.            (do-accessor name slotname (cddr inits)))))
  1980.     ((eq (car inits) :writer)
  1981.      (let ((setter (cadr inits)))
  1982.        (append (do-writer setter name slotname)
  1983.            (do-accessor name slotname (cddr inits)))))
  1984.     (t (do-accessor name slotname (cddr inits)))))
  1985.  
  1986. (defun do-reader (acc name slotname)
  1987.   `((defvar ,acc () ,(format () "The ~s slot reader" acc))
  1988.     (let ((sdsr (slot-description-slot-reader
  1989.          (find-slot-description ,name ',slotname))))
  1990.       (setq ,acc sdsr)
  1991.       (setf (symbol-function ',acc)
  1992.         (if (generic-function? sdsr)
  1993.         (generic-function-discriminating-function sdsr)
  1994.         sdsr)))))
  1995.  
  1996. (defun do-writer (setter name slotname)
  1997.   `((defvar ,setter () ,(format () "The ~s slot writer" setter))
  1998.     (let ((sdsw (slot-description-slot-writer
  1999.          (find-slot-description ,name ',slotname))))
  2000.       (setq ,setter sdsw)
  2001.       (setf (symbol-function ',setter)
  2002.         (if (generic-function? sdsw)
  2003.         (generic-function-discriminating-function sdsw)
  2004.         sdsw)))))
  2005.  
  2006. (defun do-predicates (name initargs)
  2007.   (cond ((null initargs) ())
  2008.     ((eq (car initargs) :predicate)
  2009.      (let ((pred (cadr initargs)))
  2010.        (append `((defgeneric ,pred (obj)
  2011.                :method ((obj) ())
  2012.                :method (((obj ,name)) t)))
  2013.            (do-predicates name (cddr initargs)))))
  2014.     (t (do-predicates name (cddr initargs)))))
  2015.  
  2016. (defun do-constructors (name initargs)
  2017.   (cond ((null initargs) ())
  2018.     ((eq (car initargs) :constructor)
  2019.      (let ((con (cadr initargs)))
  2020.        (cons (if (atom con)
  2021.              `(defun ,con (&rest inits)
  2022.             (apply #'make ,name inits))
  2023.              `(defun ,(car con) ,(cdr con)
  2024.             (make ,name
  2025.                   ,@(mapcan #'(lambda (init)
  2026.                         (list (symbol2key init)
  2027.                           init))
  2028.                     (cdr con)))))
  2029.          (do-constructors name (cddr initargs)))))
  2030.     (t (do-constructors name (cddr initargs)))))
  2031.  
  2032. (defun do-printfn (name initargs)
  2033.   (let ((pfn (find-key :print-function initargs ())))
  2034.     (if (null pfn)
  2035.     ()
  2036.     `((defmethod generic-prin ((obj ,name) str)
  2037.         (funcall ,pfn obj str))))))
  2038.  
  2039. ) ; end of eval-when
  2040.  
  2041. (defmacro defclass (name supers slots . initargs)
  2042. "Syntax: (defclass name (supers) (slots) {initargs}*), where
  2043. name is a symbol,
  2044. supers is {class}*,
  2045. slots is {symbol | (symbol {slot-initargs}*)}, and
  2046. initargs and slot-initargs are {key val}. Allowable initargs include
  2047. :class               the class of the class begin defined
  2048. :initargs            a list of the allowable initargs for this class
  2049. :predicate           a predicate function for this class
  2050. :constructor         a constructor function for this class
  2051. :print-function      a function to be added as a method to generic-prin
  2052.                      to print an instance
  2053. The :predicate and :constructor initargs can be repeated.
  2054. Allowable slot-initargs include
  2055. :reader              a symbol to name a reader for this slot
  2056. :writer              a symbol to name a writer for this slot
  2057. :accessor            a symbol to name a reader for this slot; a writer
  2058.                      for this slot will be installed as the setf of the
  2059.                      reader
  2060. :initform            an initial value for the slot
  2061. The :reader, :writer, and :accessor initargs can be repeated."
  2062.   `(progn
  2063.      (defvar ,name ()
  2064.        ,(find-key :documentation initargs
  2065.           (format () "The Telos class ~s" name)))
  2066.      (setq ,name
  2067.        (make ,(find-key :class initargs 'class)
  2068.          :name ',name
  2069.          :direct-superclasses
  2070.          (list ,@(if (null supers) '(object) supers))
  2071.          :direct-slot-descriptions (list ,@(do-direct-slotds slots))
  2072.          :direct-initargs
  2073.          ',(mapcar #'symbol2key (find-key :initargs initargs ()))
  2074.          ,@(filter-initargs initargs '(:initargs :predicate
  2075.                        :class :constructor
  2076.                        :print-function :documentation))))
  2077.      ,@(do-accessors name slots)
  2078.      ,@(do-predicates name initargs)
  2079.      ,@(do-constructors name initargs)
  2080.      ,@(do-printfn name initargs)
  2081.      ',name))
  2082.  
  2083. (defmacro defmetaclass (name super slots . initargs)
  2084. "See defclass for documentation."
  2085.   `(progn
  2086.      (defvar ,name ()
  2087.        ,(find-key :documentation initargs
  2088.           (format () "The Telos metaclass ~s" name)))
  2089.      (setq ,name
  2090.        (make ,(find-key :class initargs 'metaclass)
  2091.          :name ',name
  2092.          :direct-superclasses
  2093.          (list ,(if (null super) 'class super))
  2094.          :direct-slot-descriptions (list ,@(do-direct-slotds slots))
  2095.          :direct-initargs
  2096.          ',(mapcar #'symbol2key (find-key :initargs initargs ()))
  2097.          ,@(filter-initargs initargs '(:initargs :predicate
  2098.                        :class :constructor
  2099.                        :print-function :documentation))))
  2100.      ,@(do-accessors name slots)
  2101.      ,@(do-predicates name initargs)
  2102.      ,@(do-constructors name initargs)
  2103.      ,@(do-printfn name initargs)
  2104.      ',name))
  2105.  
  2106. #-telos-debug (progn
  2107.  
  2108. (defun primitive-print (obj str xx)
  2109.   (declare (ignore xx))
  2110.   (generic-prin obj str))
  2111.  
  2112. (defgeneric generic-prin (obj str))
  2113.  
  2114. (defmethod generic-prin (obj str)
  2115.   (let ((*print-case* :downcase))
  2116.     (format str "#object([~a])"
  2117.         (class-name (class-of obj)))))
  2118.  
  2119. (defmethod generic-prin ((obj class) str)
  2120.   (let ((*print-case* :downcase))
  2121.     (format str "#class(~a [~a])"
  2122.         (class-name obj)
  2123.         (class-name (class-of obj)))))
  2124.  
  2125. (defmethod generic-prin ((obj slot-description) str)
  2126.   (let ((*print-case* :downcase))
  2127.     (format str "#slotd([~a])"
  2128.         (class-name (class-of obj)))))
  2129.  
  2130. (defmethod generic-prin ((obj local-slot-description) str)
  2131.   (let ((*print-case* :downcase))
  2132.     (format str "#slotd(~a [~a])"
  2133.         (slot-description-name obj)
  2134.         (class-name (class-of obj)))))
  2135.  
  2136. (defmethod generic-prin ((obj generic-function) str)
  2137.   (let ((*print-case* :downcase))
  2138.     (format str "#gfun~a"
  2139.         (cons (generic-function-name obj)
  2140.           (mapcar #'class-name
  2141.               (generic-function-domain obj))))))
  2142.  
  2143. (defmethod generic-prin ((obj method) str)
  2144.   (let ((*print-case* :downcase))
  2145.     (format str "#method~a"
  2146.         (let ((gf (method-generic-function obj)))
  2147.           (cons (if (generic-function? gf)
  2148.             (generic-function-name gf)
  2149.             :unattached)
  2150.             (mapcar #'class-name
  2151.                 (method-domain obj)))))))
  2152.  
  2153. (defmethod generic-prin ((obj cl-object) str)
  2154.   (format str "~s" obj))
  2155.  
  2156. ) ; end of telos-debug
  2157.  
  2158. (defmethod allocate ((cl common) (inits list))
  2159.   (declare (ignore inits))
  2160.   (error "can't allocate a CL class: ~s" (class-name cl)))
  2161.  
  2162. ;----------------------------------------------------------------------
  2163.  
  2164. (defun class-hierarchy (&optional (slots? ()))
  2165.   (do-class-hierarchy (list object) 0 slots?)
  2166.   t)
  2167.  
  2168. (defun do-class-hierarchy (objlist depth slots?)
  2169.     (print-indent (car objlist) depth)
  2170.     (when slots?
  2171.       (when (class-slot-descriptions (car objlist))
  2172.     (prin-indent "slots: " depth)
  2173.     (princ (class-slots-names (car objlist)))
  2174.     (fresh-line))
  2175.       (when (class-initargs (car objlist))
  2176.     (prin-indent "initargs: " depth)
  2177.     (princ (class-initargs (car objlist)))
  2178.     (fresh-line)))
  2179.     (when (class-direct-subclasses (car objlist))
  2180.       (do-class-hierarchy (class-direct-subclasses (car objlist))
  2181.               (+ depth 4) slots?))
  2182.     (when (cdr objlist)
  2183.       (do-class-hierarchy (cdr objlist) depth slots?)))
  2184.  
  2185. (defun class-slots-names (cl)
  2186.   (mapcar #'slot-description-name
  2187.       (class-slot-descriptions cl)))
  2188.  
  2189. (defun print-indent (obj depth)
  2190.     (prin-indent obj depth)
  2191.     (fresh-line))
  2192.  
  2193. (defun prin-indent (obj depth)
  2194.   (cond ((> depth 5) (princ "     ") (prin-indent obj (- depth 5)))
  2195.     ((= depth 0) (princ obj))
  2196.     ((= depth 1) (princ " ") (princ obj))
  2197.     ((= depth 2) (princ "  ") (princ obj))
  2198.     ((= depth 3) (princ "   ") (princ obj))
  2199.     ((= depth 4) (princ "    ") (princ obj))
  2200.     ((= depth 5) (princ "     ") (princ obj))))
  2201.  
  2202. (defun instance-hierarchy ()
  2203.   (let ((classes (collect-all-classes)))
  2204.     (do-instance-hierarchy metaclass
  2205.                (remove metaclass classes)
  2206.                0)
  2207.     (length classes)))
  2208.  
  2209. (defun collect-all-classes ()
  2210.   (remove-duplicates (collect-all-classes-aux object)
  2211.              :test #'eq))
  2212.  
  2213. (defun collect-all-classes-aux (cl)
  2214.   (let ((subs (class-direct-subclasses cl)))
  2215.     (if (null subs)
  2216.     (list cl)
  2217.     (cons cl (mapcan #'(lambda (c)
  2218.                  (collect-all-classes-aux c))
  2219.              subs)))))
  2220.  
  2221. (defun direct-instance? (cl sup)
  2222.   (eq (class-of cl) sup))
  2223.  
  2224. (defun class-direct-instances (cl classes)
  2225.   (remove-if-not #'(lambda (inst)
  2226.              (direct-instance? inst cl))
  2227.          classes))
  2228.  
  2229. (defun do-instance-hierarchy (cl classes depth)
  2230.   (let ((instances (class-direct-instances cl classes)))
  2231.     (print-indent cl depth)
  2232.     (mapc #'(lambda (inst)
  2233.           (do-instance-hierarchy inst classes (+ depth 4)))
  2234.       instances)))
  2235.  
  2236. ;------------------------------------------------------------------------------
  2237.  
  2238. #-telos-debug (progn
  2239.  
  2240. (defmetaclass structure-class () ())
  2241.  
  2242. (defmethod compute-and-ensure-slot-accessors
  2243.   ((c structure-class) (effective-slotds list) (inherited-slotds list))
  2244.   (declare (ignore c inherited-slotds))
  2245.   (structure-c-a-e-s-a effective-slotds 0)
  2246.   effective-slotds)
  2247.  
  2248. (defun structure-c-a-e-s-a (effective-slotds index)
  2249.   (unless (null effective-slotds)
  2250.     (setf (slot-description-slot-reader (car effective-slotds))
  2251.       #'(lambda (obj)
  2252.           (primitive-ref obj index)))
  2253.     (setf (slot-description-slot-writer (car effective-slotds))
  2254.       #'(lambda (obj val)
  2255.           (setf (primitive-ref obj index) val)))
  2256.     (structure-c-a-e-s-a (cdr effective-slotds) (+ index 1))))
  2257.  
  2258. (defclass structure ()
  2259.   ()
  2260.   :class structure-class)
  2261.  
  2262. (defmethod initialize ((s structure) (inits list))
  2263.   (declare (ignore inits))
  2264.   (call-next-method)
  2265.   (mapc #'(lambda (sd)
  2266.         (when (eq (slot-value-using-slot-description sd s) unbound)
  2267.           (setf (slot-value-using-slot-description sd s) ())))
  2268.     (class-slot-descriptions (class-of s)))
  2269.   s)
  2270.  
  2271. (defmethod generic-prin ((s structure) str)
  2272.   (let* ((sclass (class-of s))
  2273.      (slots (class-slot-descriptions sclass))
  2274.      (names (mapcar #'slot-description-name slots))
  2275.      (vals  (mapcan #'(lambda (name sd)
  2276.                 (list name
  2277.                   (slot-value-using-slot-description sd s)))
  2278.             names slots)))
  2279.     (format str "#struct~s" (cons (class-name sclass) vals))))
  2280.  
  2281. (defmacro defstructure (name super slots . inits)
  2282.   (let ((initargs (mapcar #'(lambda (s) (if (atom s) s (car s)))
  2283.               slots))
  2284.     (slotinits
  2285.      (mapcar #'(lambda (s)
  2286.              (cond ((atom s)
  2287.                 `(,s :accessor ,(construct-name "~a-~a" name s)))
  2288.                ((and (not (member :reader (cdr s)))
  2289.                  (not (member :writer (cdr s)))
  2290.                  (not (member :accessor (cdr s))))
  2291.                 `(,(car s) :accessor ,(construct-name
  2292.                            "~a-~a"
  2293.                            name
  2294.                            (car s))
  2295.                   ,@(cdr s)))
  2296.                (t s)))
  2297.          slots)))
  2298.     `(defclass ,name (,(if (null super) 'structure super))
  2299.        ,slotinits
  2300.        ,@inits
  2301.        :initargs ,initargs
  2302.        ,@(unless (member :constructor inits)
  2303.        `(:constructor ,(construct-name "MAKE-~a" name)))
  2304.        ,@(unless (member :predicate inits)
  2305.        `(:predicate ,(construct-name "~a-P" name)))
  2306.        :class structure-class)))
  2307.  
  2308. ;------------------------------------------------------------------------------
  2309.  
  2310. (defvar *line-length* 60)
  2311.  
  2312. (defgeneric describe (obj))
  2313.  
  2314. (defmethod describe ((obj cl-object))
  2315.   (call-next-method)
  2316. #-WCL
  2317.   (lisp:describe obj))
  2318.  
  2319. (defmethod describe ((obj object))
  2320.   (let ((str1 (format () "~%~s is an instance of " obj))
  2321.     (str2 (format () "~s~%" (class-of obj))))
  2322.     (princ str1)
  2323.     (when (> (+ (length str1) (length str2)) *line-length*) (terpri))
  2324.     (princ str2))
  2325.   (let ((sds (class-slot-descriptions (class-of obj))))
  2326.     (when sds
  2327.       (let ((*print-case* :downcase))
  2328.     (mapc #'(lambda (sd)
  2329.           (let ((val (slot-value-using-slot-description sd obj)))
  2330.             (format t "~a: ~a~%" (slot-description-name sd)
  2331.                 (if (eq val unbound)
  2332.                 '<unbound>
  2333.                 val))))
  2334.           sds))))
  2335.   (values))
  2336.  
  2337. ) ; end of telos-debug
  2338.  
  2339. #+telos-debug (defun describe (x) (lisp:describe x))
  2340.  
  2341. ;------------------------------------------------------------------------------
  2342.  
  2343. (let ((*package* (find-package :user)))
  2344.   (shadowing-import '(describe
  2345.               #+KCL allocate
  2346.               #+CMU stream))
  2347. #+PCL (unuse-package :pcl)
  2348.   (use-package telos))
  2349.  
  2350. #+KCL
  2351. (eval-when (load)
  2352.   (format t "done.~%"))
  2353.